Delete flakey tests

This commit is contained in:
Simon Redman 2020-03-21 15:04:30 -07:00 committed by Nicolas Fella
parent 2e15294caf
commit b7643ecbad
7 changed files with 1 additions and 1632 deletions

View file

@ -28,12 +28,7 @@ set(kdeconnect_sms_libraries
ecm_add_test(pluginloadtest.cpp LINK_LIBRARIES ${kdeconnect_libraries})
ecm_add_test(sendfiletest.cpp LINK_LIBRARIES ${kdeconnect_libraries})
ecm_add_test(networkpackettests.cpp LINK_LIBRARIES ${kdeconnect_libraries})
ecm_add_test(testsocketlinereader.cpp TEST_NAME testsocketlinereader LINK_LIBRARIES ${kdeconnect_libraries})
ecm_add_test(testsslsocketlinereader.cpp TEST_NAME testsslsocketlinereader LINK_LIBRARIES ${kdeconnect_libraries})
ecm_add_test(kdeconnectconfigtest.cpp TEST_NAME kdeconnectconfigtest LINK_LIBRARIES ${kdeconnect_libraries})
ecm_add_test(lanlinkprovidertest.cpp TEST_NAME lanlinkprovidertest LINK_LIBRARIES ${kdeconnect_libraries})
ecm_add_test(devicetest.cpp TEST_NAME devicetest LINK_LIBRARIES ${kdeconnect_libraries})
ecm_add_test(testsocketlinereader.cpp TEST_NAME testsocketlinereader LINK_LIBRARIES ${kdeconnect_libraries})\
if (NOT SAILFISHOS)
ecm_add_test(testnotificationlistener.cpp

View file

@ -1,127 +0,0 @@
/**
* Copyright 2015 Vineet Garg <grgvineet@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 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 <https://www.gnu.org/licenses/>.
*/
#include "../core/device.h"
#include "../core/backends/lan/lanlinkprovider.h"
#include "../core/kdeconnectconfig.h"
#include <QtTest>
/**
* This class tests the working of device class
*/
class DeviceTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
void testUnpairedDevice();
void testPairedDevice();
void cleanupTestCase();
private:
QString deviceId;
QString deviceName;
QString deviceType;
NetworkPacket* identityPacket;
};
void DeviceTest::initTestCase()
{
deviceId = QStringLiteral("testdevice");
deviceName = QStringLiteral("Test Device");
deviceType = QStringLiteral("smartphone");
QString stringPacket = QStringLiteral("{\"id\":1439365924847,\"type\":\"kdeconnect.identity\",\"body\":{\"deviceId\":\"testdevice\",\"deviceName\":\"Test Device\",\"protocolVersion\":6,\"deviceType\":\"phone\"}}");
identityPacket = new NetworkPacket(QStringLiteral("kdeconnect.identity"));
NetworkPacket::unserialize(stringPacket.toLatin1(), identityPacket);
}
void DeviceTest::testPairedDevice()
{
KdeConnectConfig::instance().addTrustedDevice(deviceId, deviceName, deviceType);
KdeConnectConfig::instance().setDeviceProperty(deviceId, QStringLiteral("certificate"), QString::fromLatin1(KdeConnectConfig::instance().certificate().toPem())); // Using same certificate from kcc, instead of generating one
Device device(this, deviceId);
QCOMPARE(device.id(), deviceId);
QCOMPARE(device.name(), deviceName);
QCOMPARE(device.type(), deviceType);
QCOMPARE(device.isTrusted(), true);
QCOMPARE(device.isReachable(), false);
// Add link
LanLinkProvider linkProvider;
QSslSocket socket;
LanDeviceLink* link = new LanDeviceLink(deviceId, &linkProvider, &socket, LanDeviceLink::Locally);
device.addLink(*identityPacket, link);
QCOMPARE(device.isReachable(), true);
QCOMPARE(device.availableLinks().contains(linkProvider.name()), true);
// Remove link
device.removeLink(link);
QCOMPARE(device.isReachable(), false);
QCOMPARE(device.availableLinks().contains(linkProvider.name()), false);
device.unpair();
QCOMPARE(device.isTrusted(), false);
}
void DeviceTest::testUnpairedDevice()
{
KdeConnectConfig::instance().removeTrustedDevice(deviceId);
LanLinkProvider linkProvider;
QSslSocket socket;
LanDeviceLink* link = new LanDeviceLink(deviceId, &linkProvider, &socket, LanDeviceLink::Locally);
Device device(this, *identityPacket, link);
QCOMPARE(device.id(), deviceId);
QCOMPARE(device.name(), deviceName);
QCOMPARE(device.type(), deviceType);
QCOMPARE(device.isTrusted(), false);
QCOMPARE(device.isReachable(), true);
QCOMPARE(device.availableLinks().contains(linkProvider.name()), true);
// Remove link
device.removeLink(link);
QCOMPARE(device.isReachable(), false);
QCOMPARE(device.availableLinks().contains(linkProvider.name()), false);
}
void DeviceTest::cleanupTestCase()
{
delete identityPacket;
}
QTEST_GUILESS_MAIN(DeviceTest)
#include "devicetest.moc"

View file

@ -1,85 +0,0 @@
/**
* Copyright 2015 Vineet Garg <grgvineet@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 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 <https://www.gnu.org/licenses/>.
*/
#include "../core/kdeconnectconfig.h"
#include <QtTest>
/*
* This class tests the working of kdeconnect config that certificate and key is generated and saved properly
*/
class KdeConnectConfigTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void addTrustedDevice();
/*
void remoteCertificateTest();
*/
void removeTrustedDevice();
};
void KdeConnectConfigTest::addTrustedDevice()
{
KdeConnectConfig::instance().addTrustedDevice(QStringLiteral("testdevice"), QStringLiteral("Test Device"), QStringLiteral("phone"));
KdeConnectConfig::DeviceInfo devInfo = KdeConnectConfig::instance().getTrustedDevice(QStringLiteral("testdevice"));
QCOMPARE(devInfo.deviceName, QStringLiteral("Test Device"));
QCOMPARE(devInfo.deviceType, QStringLiteral("phone"));
}
/*
// This checks whether certificate is generated correctly and stored correctly or not
void KdeConnectConfigTest::remoteCertificateTest()
{
QSslCertificate certificate = kcc->certificate(); // Using same certificate as of device
QCOMPARE(certificate.serialNumber().toInt(0,16), 10);
QCOMPARE(certificate.subjectInfo(QSslCertificate::SubjectInfo::CommonName).first(), kcc->deviceId());
QCOMPARE(certificate.subjectInfo(QSslCertificate::SubjectInfo::Organization).first(), QString("KDE"));
QCOMPARE(certificate.subjectInfo(QSslCertificate::OrganizationalUnitName).first(), QString("Kde connect"));
kcc->setDeviceProperty("testdevice","certificate", QString::fromLatin1(certificate.toPem()));
KdeConnectConfig::DeviceInfo devInfo = kcc->getTrustedDevice("testdevice");
QSslCertificate devCertificate = QSslCertificate::fromData(devInfo.certificate.toLatin1()).first();
QCOMPARE(devCertificate.serialNumber().toInt(0,16), 10);
QCOMPARE(devCertificate.subjectInfo(QSslCertificate::SubjectInfo::CommonName).first(), kcc->deviceId());
QCOMPARE(devCertificate.subjectInfo(QSslCertificate::SubjectInfo::Organization).first(), QString("KDE"));
QCOMPARE(devCertificate.subjectInfo(QSslCertificate::OrganizationalUnitName).first(), QString("Kde connect"));
}
*/
void KdeConnectConfigTest::removeTrustedDevice()
{
KdeConnectConfig::instance().removeTrustedDevice(QStringLiteral("testdevice"));
KdeConnectConfig::DeviceInfo devInfo = KdeConnectConfig::instance().getTrustedDevice(QStringLiteral("testdevice"));
QCOMPARE(devInfo.deviceName, QStringLiteral("unnamed"));
QCOMPARE(devInfo.deviceType, QStringLiteral("unknown"));
}
QTEST_GUILESS_MAIN(KdeConnectConfigTest)
#include "kdeconnectconfigtest.moc"

View file

@ -1,454 +0,0 @@
/**
* Copyright 2015 Vineet Garg <grgvineet@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 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 <https://www.gnu.org/licenses/>.
*/
// This class tests the behaviour of the class LanLinkProvider, be sure to kill process kdeconnectd to avoid any port binding issues
#include "../core/backends/lan/lanlinkprovider.h"
#include "../core/backends/lan/server.h"
#include "../core/backends/lan/socketlinereader.h"
#include "../core/kdeconnectconfig.h"
#include <QAbstractSocket>
#include <QSslSocket>
#include <QtTest>
#include <QSslKey>
#include <QUdpSocket>
#include <QtCrypto>
#include <QMetaEnum>
/*
* This class tests the working of LanLinkProvider under different conditions that when identity packet is received over TCP, over UDP and same when the device is paired.
* It depends on KdeConnectConfig since LanLinkProvider internally uses it.
*/
class LanLinkProviderTest : public QObject
{
Q_OBJECT
public:
explicit LanLinkProviderTest()
: m_lanLinkProvider(true)
, m_server(nullptr)
, m_reader(nullptr)
, m_udpSocket(nullptr)
{
QStandardPaths::setTestModeEnabled(true);
}
public Q_SLOTS:
void initTestCase();
void init();
void cleanup();
private Q_SLOTS:
/**
* Test that the LanLinkProvider will send an identity packet to a non-default port
*/
void testChangedUDPBroadcastPort();
/**
* Test that the LanLinkProvider will receive an identity packet on a non-default port
*/
void testChangedUDPListenPort();
void pairedDeviceTcpPacketReceived();
void pairedDeviceUdpPacketReceived();
void unpairedDeviceTcpPacketReceived();
void unpairedDeviceUdpPacketReceived();
private:
const int TEST_PORT = 8520;
// Add some private fields here
LanLinkProvider m_lanLinkProvider;
Server* m_server;
SocketLineReader* m_reader;
QUdpSocket* m_udpSocket;
QString m_identityPacket;
// Attributes for test device
QString m_deviceId;
QString m_name;
QCA::PrivateKey m_privateKey;
QSslCertificate m_certificate;
QSslCertificate generateCertificate(QString&, QCA::PrivateKey&);
void addTrustedDevice();
void removeTrustedDevice();
void setSocketAttributes(QSslSocket* socket);
void testIdentityPacket(QByteArray& identityPacket);
void socketBindErrorFail(const QUdpSocket& socket);
};
void LanLinkProviderTest::initTestCase()
{
removeTrustedDevice(); // Remove trusted device if left by chance by any test
m_deviceId = QStringLiteral("testdevice");
m_name = QStringLiteral("Test Device");
m_privateKey = QCA::KeyGenerator().createRSA(2048);
m_certificate = generateCertificate(m_deviceId, m_privateKey);
m_identityPacket = QStringLiteral("{\"id\":1439365924847,\"type\":\"kdeconnect.identity\",\"body\":{\"deviceId\":\"testdevice\",\"deviceName\":\"Test Device\",\"protocolVersion\":6,\"deviceType\":\"phone\",\"tcpPort\":") + QString::number(TEST_PORT) + QStringLiteral("}}");
}
void LanLinkProviderTest::init()
{
m_lanLinkProvider.onStart();
}
void LanLinkProviderTest::cleanup()
{
m_lanLinkProvider.onStop();
}
void LanLinkProviderTest::testChangedUDPBroadcastPort()
{
quint16 udpListenPort = LanLinkProvider::UDP_PORT;
quint16 udpBroadcastPort = LanLinkProvider::UDP_PORT + 1;
m_lanLinkProvider.onStop();
LanLinkProvider testlanLinkProvider(true, udpBroadcastPort, udpListenPort);
testlanLinkProvider.onStart();
QUdpSocket mUdpServer;
bool bindSuccessful = mUdpServer.bind(QHostAddress::LocalHost, udpBroadcastPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
if (!bindSuccessful) {
socketBindErrorFail(mUdpServer);
}
QSignalSpy spy(&mUdpServer, SIGNAL(readyRead()));
testlanLinkProvider.onNetworkChange();
QVERIFY2(!spy.isEmpty() || spy.wait(), "Did not receive UDP packet");
}
void LanLinkProviderTest::testChangedUDPListenPort()
{
quint16 udpListenPort = LanLinkProvider::UDP_PORT + 1;
quint16 udpBroadcastPort = LanLinkProvider::UDP_PORT;
m_lanLinkProvider.onStop();
LanLinkProvider testlanLinkProvider(true, udpBroadcastPort, udpListenPort);
testlanLinkProvider.onStart();
m_server = new Server(this);
QUdpSocket testUdpSocket;
m_server->listen(QHostAddress::LocalHost, TEST_PORT);
QSignalSpy spy(m_server, SIGNAL(newConnection()));
// Write an identity packet to udp socket here. We do not broadcast it here.
qint64 bytesWritten = testUdpSocket.writeDatagram(m_identityPacket.toLatin1(), QHostAddress::LocalHost, udpListenPort);
QCOMPARE(bytesWritten, m_identityPacket.size());
// In response to receiving an identity packet, the LanLinkProvider should try to open a TCP connection to us
QVERIFY(!spy.isEmpty() || spy.wait());
QSslSocket* serverSocket = m_server->nextPendingConnection();
QVERIFY2(serverSocket != 0, "Server socket is null");
QVERIFY2(serverSocket->isOpen(), "Server socket already closed");
delete m_server;
}
void LanLinkProviderTest::pairedDeviceTcpPacketReceived()
{
quint16 udpListenPort = LanLinkProvider::UDP_PORT;
quint16 udpBroadcastPort = LanLinkProvider::UDP_PORT + 1;
m_lanLinkProvider.onStop();
LanLinkProvider testlanLinkProvider(true, udpBroadcastPort, udpListenPort);
testlanLinkProvider.onStart();
addTrustedDevice();
QUdpSocket* mUdpServer = new QUdpSocket;
bool bindSuccessful = mUdpServer->bind(QHostAddress::LocalHost, udpBroadcastPort, QUdpSocket::ShareAddress);
if (!bindSuccessful) {
socketBindErrorFail(*mUdpServer);
}
QSignalSpy spy(mUdpServer, SIGNAL(readyRead()));
testlanLinkProvider.onNetworkChange();
QVERIFY(!spy.isEmpty() || spy.wait());
QByteArray datagram;
datagram.resize(mUdpServer->pendingDatagramSize());
QHostAddress sender;
mUdpServer->readDatagram(datagram.data(), datagram.size(), &sender);
testIdentityPacket(datagram);
QJsonDocument jsonDocument = QJsonDocument::fromJson(datagram);
QJsonObject body = jsonDocument.object().value(QStringLiteral("body")).toObject();
int tcpPort = body.value(QStringLiteral("tcpPort")).toInt();
QSslSocket socket;
QSignalSpy spy2(&socket, SIGNAL(connected()));
socket.connectToHost(sender, tcpPort);
QVERIFY(spy2.wait());
QVERIFY2(socket.isOpen(), "Socket disconnected immediately");
socket.write(m_identityPacket.toLatin1());
socket.waitForBytesWritten(2000);
QSignalSpy spy3(&socket, SIGNAL(encrypted()));
setSocketAttributes(&socket);
socket.addCaCertificate(KdeConnectConfig::instance().certificate());
socket.setPeerVerifyMode(QSslSocket::VerifyPeer);
socket.setPeerVerifyName(KdeConnectConfig::instance().name());
socket.startServerEncryption();
QVERIFY(spy3.wait());
QCOMPARE(socket.sslErrors().size(), 0);
QVERIFY2(socket.isValid(), "Server socket disconnected");
QVERIFY2(socket.isEncrypted(), "Server socket not yet encrypted");
QVERIFY2(!socket.peerCertificate().isNull(), "Peer certificate is null");
removeTrustedDevice();
delete mUdpServer;
}
void LanLinkProviderTest::pairedDeviceUdpPacketReceived()
{
addTrustedDevice();
m_server = new Server(this);
m_udpSocket = new QUdpSocket(this);
m_server->listen(QHostAddress::LocalHost, TEST_PORT);
QSignalSpy spy(m_server, SIGNAL(newConnection()));
qint64 bytesWritten = m_udpSocket->writeDatagram(m_identityPacket.toLatin1(), QHostAddress::LocalHost, LanLinkProvider::UDP_PORT); // write an identity packet to udp socket here, we do not broadcast it here
QCOMPARE(bytesWritten, m_identityPacket.size());
// We should have an incoming connection now, wait for incoming connection
QVERIFY(!spy.isEmpty() || spy.wait());
QSslSocket* serverSocket = m_server->nextPendingConnection();
QVERIFY2(serverSocket != 0, "Server socket is null");
QVERIFY2(serverSocket->isOpen(), "Server socket already closed");
m_reader = new SocketLineReader(serverSocket, this);
QSignalSpy spy2(m_reader, SIGNAL(readyRead()));
QVERIFY(spy2.wait());
QByteArray receivedPacket = m_reader->readLine();
testIdentityPacket(receivedPacket);
// Received identity packet from LanLinkProvider now start ssl
QSignalSpy spy3(serverSocket, SIGNAL(encrypted()));
QVERIFY(connect(serverSocket, static_cast<void(QAbstractSocket::*)(QAbstractSocket::SocketError)>(&QSslSocket::error),
this, [](QAbstractSocket::SocketError error){ qDebug() << "error:" << error; }));
setSocketAttributes(serverSocket);
serverSocket->addCaCertificate(KdeConnectConfig::instance().certificate());
serverSocket->setPeerVerifyMode(QSslSocket::VerifyPeer);
serverSocket->setPeerVerifyName(KdeConnectConfig::instance().deviceId());
serverSocket->startClientEncryption(); // Its TCP server. but SSL client
QVERIFY(!serverSocket->isEncrypted());
spy3.wait(2000);
qDebug() << "xxxxxxxxx" << serverSocket->sslErrors();
QCOMPARE(serverSocket->sslErrors().size(), 0);
QVERIFY2(serverSocket->isValid(), "Server socket disconnected");
QVERIFY2(serverSocket->isEncrypted(), "Server socket not yet encrypted");
QVERIFY2(!serverSocket->peerCertificate().isNull(), "Peer certificate is null");
removeTrustedDevice();
delete m_server;
delete m_udpSocket;
}
void LanLinkProviderTest::unpairedDeviceTcpPacketReceived()
{
quint16 udpListenPort = LanLinkProvider::UDP_PORT;
quint16 udpBroadcastPort = LanLinkProvider::UDP_PORT + 1;
m_lanLinkProvider.onStop();
LanLinkProvider testlanLinkProvider(true, udpBroadcastPort, udpListenPort);
testlanLinkProvider.onStart();
QUdpSocket* mUdpServer = new QUdpSocket;
bool bindSuccessful = mUdpServer->bind(QHostAddress::LocalHost, udpBroadcastPort, QUdpSocket::ShareAddress);
if (!bindSuccessful) {
socketBindErrorFail(*mUdpServer);
}
QSignalSpy spy(mUdpServer, SIGNAL(readyRead()));
testlanLinkProvider.onNetworkChange();
QVERIFY(!spy.isEmpty() || spy.wait());
QByteArray datagram;
datagram.resize(mUdpServer->pendingDatagramSize());
QHostAddress sender;
mUdpServer->readDatagram(datagram.data(), datagram.size(), &sender);
testIdentityPacket(datagram);
QJsonDocument jsonDocument = QJsonDocument::fromJson(datagram);
QJsonObject body = jsonDocument.object().value(QStringLiteral("body")).toObject();
int tcpPort = body.value(QStringLiteral("tcpPort")).toInt();
QSslSocket socket;
QSignalSpy spy2(&socket, SIGNAL(connected()));
socket.connectToHost(sender, tcpPort);
QVERIFY(spy2.wait());
QVERIFY2(socket.isOpen(), "Socket disconnected immediately");
socket.write(m_identityPacket.toLatin1());
socket.waitForBytesWritten(2000);
QSignalSpy spy3(&socket, SIGNAL(encrypted()));
// We don't take care for sslErrors signal here, but signal will emit still we will get successful connection
setSocketAttributes(&socket);
socket.setPeerVerifyMode(QSslSocket::QueryPeer);
socket.startServerEncryption();
QVERIFY(spy3.wait());
QVERIFY2(socket.isValid(), "Server socket disconnected");
QVERIFY2(socket.isEncrypted(), "Server socket not yet encrypted");
QVERIFY2(!socket.peerCertificate().isNull(), "Peer certificate is null");
delete mUdpServer;
}
void LanLinkProviderTest::unpairedDeviceUdpPacketReceived()
{
m_server = new Server(this);
m_udpSocket = new QUdpSocket(this);
m_server->listen(QHostAddress::LocalHost, TEST_PORT);
QSignalSpy spy(m_server, &Server::newConnection);
qint64 bytesWritten = m_udpSocket->writeDatagram(m_identityPacket.toLatin1(), QHostAddress::LocalHost, LanLinkProvider::UDP_PORT); // write an identity packet to udp socket here, we do not broadcast it here
QCOMPARE(bytesWritten, m_identityPacket.size());
QVERIFY(!spy.isEmpty() || spy.wait());
QSslSocket* serverSocket = m_server->nextPendingConnection();
QVERIFY2(serverSocket != 0, "Server socket is null");
QVERIFY2(serverSocket->isOpen(), "Server socket already closed");
m_reader = new SocketLineReader(serverSocket, this);
QSignalSpy spy2(m_reader, &SocketLineReader::readyRead);
QVERIFY(spy2.wait());
QByteArray receivedPacket = m_reader->readLine();
QVERIFY2(!receivedPacket.isEmpty(), "Empty packet received");
testIdentityPacket(receivedPacket);
// Received identity packet from LanLinkProvider now start ssl
QSignalSpy spy3(serverSocket, SIGNAL(encrypted()));
setSocketAttributes(serverSocket);
serverSocket->setPeerVerifyMode(QSslSocket::QueryPeer);
serverSocket->startClientEncryption(); // Its TCP server. but SSL client
QVERIFY(spy3.wait());
QVERIFY2(serverSocket->isValid(), "Server socket disconnected");
QVERIFY2(serverSocket->isEncrypted(), "Server socket not yet encrypted");
QVERIFY2(!serverSocket->peerCertificate().isNull(), "Peer certificate is null");
delete m_server;
delete m_udpSocket;
}
void LanLinkProviderTest::testIdentityPacket(QByteArray& identityPacket)
{
QJsonDocument jsonDocument = QJsonDocument::fromJson(identityPacket);
QJsonObject jsonObject = jsonDocument.object();
QJsonObject body = jsonObject.value(QStringLiteral("body")).toObject();
QCOMPARE(jsonObject.value(QStringLiteral("type")).toString(), QStringLiteral("kdeconnect.identity"));
QVERIFY2(body.contains(QStringLiteral("deviceName")), "Device name not found in identity packet");
QVERIFY2(body.contains(QStringLiteral("deviceId")), "Device id not found in identity packet");
QVERIFY2(body.contains(QStringLiteral("protocolVersion")), "Protocol version not found in identity packet");
QVERIFY2(body.contains(QStringLiteral("deviceType")), "Device type not found in identity packet");
}
QSslCertificate LanLinkProviderTest::generateCertificate(QString& commonName, QCA::PrivateKey& privateKey)
{
QDateTime startTime = QDateTime::currentDateTime();
QDateTime endTime = startTime.addYears(10);
QCA::CertificateInfo certificateInfo;
certificateInfo.insert(QCA::CommonName,commonName);
certificateInfo.insert(QCA::Organization,QStringLiteral("KDE"));
certificateInfo.insert(QCA::OrganizationalUnit,QStringLiteral("Kde connect"));
QCA::CertificateOptions certificateOptions(QCA::PKCS10);
certificateOptions.setSerialNumber(10);
certificateOptions.setInfo(certificateInfo);
certificateOptions.setValidityPeriod(startTime, endTime);
certificateOptions.setFormat(QCA::PKCS10);
QSslCertificate certificate = QSslCertificate(QCA::Certificate(certificateOptions, privateKey).toPEM().toLatin1());
return certificate;
}
void LanLinkProviderTest::setSocketAttributes(QSslSocket* socket)
{
socket->setPrivateKey(QSslKey(m_privateKey.toPEM().toLatin1(), QSsl::Rsa));
socket->setLocalCertificate(m_certificate);
}
void LanLinkProviderTest::addTrustedDevice()
{
KdeConnectConfig::instance().addTrustedDevice(m_deviceId, m_name, QStringLiteral("phone"));
KdeConnectConfig::instance().setDeviceProperty(m_deviceId, QStringLiteral("certificate"), QString::fromLatin1(m_certificate.toPem()));
}
void LanLinkProviderTest::removeTrustedDevice()
{
KdeConnectConfig::instance().removeTrustedDevice(m_deviceId);
}
void LanLinkProviderTest::socketBindErrorFail(const QUdpSocket& socket)
{
QAbstractSocket::SocketError sockErr = socket.error();
// Refer to https://doc.qt.io/qt-5/qabstractsocket.html#SocketError-enum to decode socket error number
QString errorMessage = QLatin1String("Failed to bind UDP socket with error ");
errorMessage = errorMessage + QString::fromLatin1(QMetaEnum::fromType<QAbstractSocket::SocketError>().valueToKey(sockErr));
QFAIL(errorMessage.toLocal8Bit().data());
}
QTEST_GUILESS_MAIN(LanLinkProviderTest)
#include "lanlinkprovidertest.moc"

View file

@ -1,143 +0,0 @@
/**
* Copyright 2013 Albert Vaca <albertvaka@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 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 <https://www.gnu.org/licenses/>.
*/
#include "networkpackettests.h"
#include "core/networkpacket.h"
#include <QtTest>
#include <QBuffer>
QTEST_GUILESS_MAIN(NetworkPacketTests);
void NetworkPacketTests::initTestCase()
{
// Called before the first testfunction is executed
}
void NetworkPacketTests::networkPacketTest()
{
NetworkPacket np(QStringLiteral("com.test"));
np.set(QStringLiteral("hello"), QStringLiteral("hola"));
QCOMPARE( (np.get<QString>(QStringLiteral("hello"), QStringLiteral("bye"))) , QStringLiteral("hola") );
np.set(QStringLiteral("hello"), QString());
QCOMPARE((np.get<QString>(QStringLiteral("hello"), QStringLiteral("bye"))) , QString());
np.body().remove(QStringLiteral("hello"));
QCOMPARE((np.get<QString>(QStringLiteral("hello"), QStringLiteral("bye"))) , QStringLiteral("bye"));
np.set(QStringLiteral("foo"), QStringLiteral("bar"));
QByteArray ba = np.serialize();
//qDebug() << "Serialized packet:" << ba;
NetworkPacket np2(QLatin1String(""));
NetworkPacket::unserialize(ba,&np2);
QCOMPARE( np.id(), np2.id() );
QCOMPARE( np.type(), np2.type() );
QCOMPARE( np.body(), np2.body() );
QByteArray json("{\"id\":\"123\",\"type\":\"test\",\"body\":{\"testing\":true}}");
//qDebug() << json;
NetworkPacket::unserialize(json,&np2);
QCOMPARE( np2.id(), QStringLiteral("123") );
QCOMPARE( (np2.get<bool>(QStringLiteral("testing"))), true );
QCOMPARE( (np2.get<bool>(QStringLiteral("not_testing"))), false );
QCOMPARE( (np2.get<bool>(QStringLiteral("not_testing"),true)), true );
//NetworkPacket::unserialize("this is not json",&np2);
//QtTest::ignoreMessage(QtSystemMsg, "json_parser - syntax error found, forcing abort, Line 1 Column 0");
//QtTest::ignoreMessage(QtDebugMsg, "Unserialization error: 1 \"syntax error, unexpected string\"");
}
void NetworkPacketTests::networkPacketIdentityTest()
{
NetworkPacket np(QLatin1String(""));
NetworkPacket::createIdentityPacket(&np);
QCOMPARE( np.get<int>(QStringLiteral("protocolVersion"), -1) , NetworkPacket::s_protocolVersion );
QCOMPARE( np.type() , PACKET_TYPE_IDENTITY );
}
void NetworkPacketTests::networkPacketPayloadTest()
{
QByteArray json;
NetworkPacket np;
// empty package
np = NetworkPacket(QStringLiteral("com.test"));
json = np.serialize();
qDebug() << json;
QVERIFY(!json.contains("\"payloadSize\""));
QVERIFY(!json.contains("\"payloadTransferInfo\""));
// package with payload
QByteArray buffer("test data");
auto payload = QSharedPointer<QIODevice>(new QBuffer(&buffer, this));
np = NetworkPacket(QStringLiteral("com.test"));
np.setPayload(payload, buffer.size());
json = np.serialize();
qDebug() << json;
QVERIFY(json.contains("\"payloadSize\":9"));
QVERIFY(json.contains("\"payloadTransferInfo\""));
// package with empty payload
QByteArray emptyBuffer("test data");
auto emptyPayload = QSharedPointer<QIODevice>(new QBuffer(&emptyBuffer, this));
np = NetworkPacket(QStringLiteral("com.test"));
np.setPayload(emptyPayload, 0);
json = np.serialize();
qDebug() << json;
QVERIFY(!json.contains("\"payloadSize\""));
QVERIFY(!json.contains("\"payloadTransferInfo\""));
// incoming package without payload
np = NetworkPacket();
QVERIFY(NetworkPacket::unserialize(
"{\"body\":{},\"id\":\"1578136807254\",\"type\":\"com.test\"}\n", &np));
QVERIFY(!np.hasPayload());
// incoming package without payload (but with payload keys)
np = NetworkPacket();
QVERIFY(NetworkPacket::unserialize(
"{\"body\":{},\"id\":\"1578136807254\",\"payloadSize\":0,\"payloadTransferInfo\":{},\"type\":\"com.test\"}\n", &np));
QVERIFY(!np.hasPayload());
}
void NetworkPacketTests::cleanupTestCase()
{
// Called after the last testfunction was executed
}
void NetworkPacketTests::init()
{
// Called before each testfunction is executed
}
void NetworkPacketTests::cleanup()
{
// Called after every testfunction
}

View file

@ -1,456 +0,0 @@
/**
* Copyright 2015 Holger Kaelberer <holger.k@elberer.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 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 <https://www.gnu.org/licenses/>.
*/
#include <QSocketNotifier>
#include <QApplication>
#include <QNetworkAccessManager>
#include <QTest>
#include <QBuffer>
#include <QStandardPaths>
#include <QImage>
#include <QColor>
#include <kiconloader.h>
#include "core/daemon.h"
#include "core/device.h"
#include "testdevice.h"
#include "core/kdeconnectplugin.h"
#include "kdeconnect-version.h"
#include "plugins/sendnotifications/sendnotificationsplugin.h"
#include "plugins/sendnotifications/notificationslistener.h"
#include "plugins/sendnotifications/notifyingapplication.h"
// Tweaked NotificationsPlugin for testing
class TestNotificationsPlugin : public SendNotificationsPlugin
{
Q_OBJECT
public:
explicit TestNotificationsPlugin(QObject* parent, const QVariantList& args)
: SendNotificationsPlugin(parent, args)
{
}
~TestNotificationsPlugin() override = default;
// allow to access notificationsListener for testing:
NotificationsListener* getNotificationsListener() const
{
return notificationsListener;
}
void setNotificationsListener(NotificationsListener* value)
{
notificationsListener = value;
}
};
// Tweaked NotificationsListener for testing:
class TestedNotificationsListener: public NotificationsListener
{
Q_OBJECT
public:
explicit TestedNotificationsListener(KdeConnectPlugin* aPlugin)
: NotificationsListener(aPlugin)
{}
~TestedNotificationsListener() override
{}
QHash<QString, NotifyingApplication>& getApplications()
{
return m_applications;
}
void setApplications(const QHash<QString, NotifyingApplication>& value)
{
m_applications = value;
}
QSharedPointer<QIODevice> iconForIconName(const QString& iconName) const {
return NotificationsListener::iconForIconName(iconName);
}
protected:
bool parseImageDataArgument(const QVariant& argument, int& width,
int& height, int& rowStride, int& bitsPerSample,
int& channels, bool& hasAlpha,
QByteArray& imageData) const override
{
width = argument.toMap().value(QStringLiteral("width")).toInt();
height = argument.toMap().value(QStringLiteral("height")).toInt();
rowStride = argument.toMap().value(QStringLiteral("rowStride")).toInt();
bitsPerSample = argument.toMap().value(QStringLiteral("bitsPerSample")).toInt();
channels = argument.toMap().value(QStringLiteral("channels")).toInt();
hasAlpha = argument.toMap().value(QStringLiteral("hasAlpha")).toBool();
imageData = argument.toMap().value(QStringLiteral("imageData")).toByteArray();
return true;
}
};
class TestNotificationListener : public QObject
{
Q_OBJECT
public:
TestNotificationListener()
: plugin(nullptr)
{
QStandardPaths::setTestModeEnabled(true);
}
private Q_SLOTS:
void testNotify();
private:
TestNotificationsPlugin* plugin;
};
void TestNotificationListener::testNotify()
{
//
// set things up:
//
QString dId(QStringLiteral("testid"));
TestDevice* d = new TestDevice(nullptr, dId);
int proxiedNotifications = 0;
QCOMPARE(proxiedNotifications, d->getSentPackets());
plugin = new TestNotificationsPlugin(this,
QVariantList({ QVariant::fromValue<Device*>(d),
QStringLiteral("notifications_plugin"),
{QStringLiteral("kdeconnect.notification")},
QStringLiteral("preferences-desktop-notification")}));
QVERIFY(plugin->getNotificationsListener());
delete plugin->getNotificationsListener();
// inject our tweaked NotificationsListener:
TestedNotificationsListener* listener = new TestedNotificationsListener(plugin);
QVERIFY(listener);
plugin->setNotificationsListener(listener);
QCOMPARE(listener, plugin->getNotificationsListener());
// make sure config is default:
plugin->config()->set(QStringLiteral("generalPersistent"), false);
plugin->config()->set(QStringLiteral("generalIncludeBody"), true);
plugin->config()->set(QStringLiteral("generalUrgency"), 0);
QCOMPARE(plugin->config()->get<bool>(QStringLiteral("generalPersistent")), false);
QCOMPARE(plugin->config()->get<bool>(QStringLiteral("generalIncludeBody")), true);
QCOMPARE(plugin->config()->get<bool>(QStringLiteral("generalUrgency")), false);
// applications are modified directly:
listener->getApplications().clear();
QCOMPARE(listener->getApplications().count(), 0);
//
// Go !!!
//
uint replacesId = 99;
uint retId;
QString appName(QStringLiteral("some-appName"));
QString body(QStringLiteral("some-body"));
QString icon(QStringLiteral("some-icon"));
QString summary(QStringLiteral("some-summary"));
// regular Notify call that is synchronized ...
retId = listener->Notify(appName, replacesId, icon, summary, body, {}, {{}}, 0);
// ... should return replacesId,
QCOMPARE(retId, replacesId);
// ... have triggered sending a packet
QCOMPARE(++proxiedNotifications, d->getSentPackets());
// ... with our properties,
QCOMPARE(d->getLastPacket()->get<uint>(QStringLiteral("id")), replacesId);
QCOMPARE(d->getLastPacket()->get<QString>(QStringLiteral("appName")), appName);
QCOMPARE(d->getLastPacket()->get<QString>(QStringLiteral("ticker")), summary + QStringLiteral(": ") + body);
QCOMPARE(d->getLastPacket()->get<bool>(QStringLiteral("isClearable")), true);
QCOMPARE(d->getLastPacket()->hasPayload(), false);
// ... and create a new application internally that is initialized correctly:
QCOMPARE(listener->getApplications().count(), 1);
QVERIFY(listener->getApplications().contains(appName));
QVERIFY(listener->getApplications()[appName].active);
QCOMPARE(listener->getApplications()[appName].name, appName);
QVERIFY(listener->getApplications()[appName].blacklistExpression.pattern().isEmpty());
QCOMPARE(listener->getApplications()[appName].name, appName);
QCOMPARE(listener->getApplications()[appName].icon, icon);
// another one, with other timeout and urgency values:
QString appName2(QStringLiteral("some-appName2"));
QString body2(QStringLiteral("some-body2"));
QString icon2(QStringLiteral("some-icon2"));
QString summary2(QStringLiteral("some-summary2"));
retId = listener->Notify(appName2, replacesId+1, icon2, summary2, body2, {}, {{QStringLiteral("urgency"), 2}}, 10);
QCOMPARE(retId, replacesId+1);
QCOMPARE(++proxiedNotifications, d->getSentPackets());
QCOMPARE(d->getLastPacket()->get<uint>(QStringLiteral("id")), replacesId+1);
QCOMPARE(d->getLastPacket()->get<QString>(QStringLiteral("appName")), appName2);
QCOMPARE(d->getLastPacket()->get<QString>(QStringLiteral("ticker")), summary2 + QStringLiteral(": ") + body2);
QCOMPARE(d->getLastPacket()->get<bool>(QStringLiteral("isClearable")), false); // timeout != 0
QCOMPARE(d->getLastPacket()->hasPayload(), false);
QCOMPARE(listener->getApplications().count(), 2);
QVERIFY(listener->getApplications().contains(appName2));
QVERIFY(listener->getApplications().contains(appName));
// if persistent-only is set, timeouts > 0 are not synced:
plugin->config()->set(QStringLiteral("generalPersistent"), true);
retId = listener->Notify(appName, replacesId, icon, summary, body, {}, {{}}, 1);
QCOMPARE(retId, 0U);
QCOMPARE(proxiedNotifications, d->getSentPackets());
retId = listener->Notify(appName2, replacesId, icon2, summary2, body2, {}, {{}}, 3);
QCOMPARE(retId, 0U);
QCOMPARE(proxiedNotifications, d->getSentPackets());
// but timeout == 0 is
retId = listener->Notify(appName, replacesId, icon, summary, body, {}, {{}}, 0);
QCOMPARE(retId, replacesId);
QCOMPARE(++proxiedNotifications, d->getSentPackets());
plugin->config()->set(QStringLiteral("generalPersistent"), false);
// if min-urgency is set, lower urgency levels are not synced:
plugin->config()->set(QStringLiteral("generalUrgency"), 1);
retId = listener->Notify(appName, replacesId, icon, summary, body, {}, {{QStringLiteral("urgency"), 0}}, 0);
QCOMPARE(retId, 0U);
QCOMPARE(proxiedNotifications, d->getSentPackets());
// equal urgency is
retId = listener->Notify(appName, replacesId, icon, summary, body, {}, {{QStringLiteral("urgency"), 1}}, 0);
QCOMPARE(retId, replacesId);
QCOMPARE(++proxiedNotifications, d->getSentPackets());
// higher urgency as well
retId = listener->Notify(appName, replacesId, icon, summary, body, {}, {{QStringLiteral("urgency"), 2}}, 0);
QCOMPARE(retId, replacesId);
QCOMPARE(++proxiedNotifications, d->getSentPackets());
plugin->config()->set(QStringLiteral("generalUrgency"), 0);
// notifications for a deactivated application are not synced:
QVERIFY(listener->getApplications().contains(appName));
listener->getApplications()[appName].active = false;
QVERIFY(!listener->getApplications()[appName].active);
retId = listener->Notify(appName, replacesId, icon, summary, body, {}, {{QStringLiteral("urgency"), 0}}, 0);
QCOMPARE(retId, 0U);
QCOMPARE(proxiedNotifications, d->getSentPackets());
// others are still:
retId = listener->Notify(appName2, replacesId+1, icon2, summary2, body2, {}, {{}}, 0);
QCOMPARE(retId, replacesId+1);
QCOMPARE(++proxiedNotifications, d->getSentPackets());
// back to normal:
listener->getApplications()[appName].active = true;
QVERIFY(listener->getApplications()[appName].active);
retId = listener->Notify(appName, replacesId, icon, summary, body, {}, {{}}, 0);
QCOMPARE(retId, replacesId);
QCOMPARE(++proxiedNotifications, d->getSentPackets());
// notifications with blacklisted subjects are not synced:
QVERIFY(listener->getApplications().contains(appName));
listener->getApplications()[appName].blacklistExpression.setPattern(QStringLiteral("black[12]|foo(bar|baz)"));
retId = listener->Notify(appName, replacesId, icon, QStringLiteral("summary black1"), body, {}, {{}}, 0);
QCOMPARE(retId, 0U);
QCOMPARE(proxiedNotifications, d->getSentPackets());
retId = listener->Notify(appName, replacesId, icon, QStringLiteral("summary foobar"), body, {}, {{}}, 0);
QCOMPARE(retId, 0U);
QCOMPARE(proxiedNotifications, d->getSentPackets());
// other subjects are synced:
retId = listener->Notify(appName, replacesId, icon, QStringLiteral("summary foo"), body, {}, {{}}, 0);
QCOMPARE(retId, replacesId);
QCOMPARE(++proxiedNotifications, d->getSentPackets());
retId = listener->Notify(appName, replacesId, icon, QStringLiteral("summary black3"), body, {}, {{}}, 0);
QCOMPARE(retId, replacesId);
QCOMPARE(++proxiedNotifications, d->getSentPackets());
// also body is checked by blacklist if requested:
plugin->config()->set(QStringLiteral("generalIncludeBody"), true);
retId = listener->Notify(appName, replacesId, icon, summary, QStringLiteral("body black1"), {}, {{}}, 0);
QCOMPARE(retId, 0U);
QCOMPARE(proxiedNotifications, d->getSentPackets());
retId = listener->Notify(appName, replacesId, icon, summary, QStringLiteral("body foobaz"), {}, {{}}, 0);
QCOMPARE(retId, 0U);
QCOMPARE(proxiedNotifications, d->getSentPackets());
// body does not matter if inclusion was not requested:
plugin->config()->set(QStringLiteral("generalIncludeBody"), false);
retId = listener->Notify(appName, replacesId, icon, summary, QStringLiteral("body black1"), {}, {{}}, 0);
QCOMPARE(retId, replacesId);
QCOMPARE(++proxiedNotifications, d->getSentPackets());
// without body, also ticker value is different:
QCOMPARE(d->getLastPacket()->get<QString>(QStringLiteral("ticker")), summary);
retId = listener->Notify(appName, replacesId, icon, summary, QStringLiteral("body foobaz"), {}, {{}}, 0);
QCOMPARE(retId, replacesId);
QCOMPARE(++proxiedNotifications, d->getSentPackets());
// back to normal:
listener->getApplications()[appName].blacklistExpression.setPattern(QLatin1String(""));
plugin->config()->set(QStringLiteral("generalIncludeBody"), true);
retId = listener->Notify(appName, replacesId, icon, summary, body, {}, {{}}, 0);
QCOMPARE(retId, replacesId);
QCOMPARE(++proxiedNotifications, d->getSentPackets());
retId = listener->Notify(appName2, replacesId, icon2, summary2, body2, {}, {{}}, 0);
QCOMPARE(retId, replacesId);
QCOMPARE(++proxiedNotifications, d->getSentPackets());
// icon synchronization:
QStringList iconPaths;
// appIcon
int count = 0;
const QStringList icons = KIconLoader::global()->queryIcons(-KIconLoader::SizeEnormous, KIconLoader::Application);
for (const auto& iconName : icons) {
if (!iconName.endsWith(QLatin1String(".png")))
continue;
if (count++ > 3) // max 3 iterations
break;
iconPaths.append(iconName); // memorize some paths for later
// existing icons are sync-ed if requested
plugin->config()->set(QStringLiteral("generalSynchronizeIcons"), true);
QFileInfo fi(iconName);
retId = listener->Notify(appName, replacesId, fi.baseName(), summary, body, {}, {{}}, 0);
QCOMPARE(retId, replacesId);
QCOMPARE(++proxiedNotifications, d->getSentPackets());
QVERIFY(d->getLastPacket()->hasPayload());
QCOMPARE(d->getLastPacket()->payloadSize(), listener->iconForIconName(fi.baseName())->size());
// works also with absolute paths
retId = listener->Notify(appName, replacesId, iconName, summary, body, {}, {{}}, 0);
QCOMPARE(retId, replacesId);
QCOMPARE(++proxiedNotifications, d->getSentPackets());
QVERIFY(d->getLastPacket()->hasPayload());
QCOMPARE(d->getLastPacket()->payloadSize(), fi.size());
// extensions other than png are not accepted:
retId = listener->Notify(appName, replacesId, iconName + QStringLiteral(".svg"), summary, body, {}, {{}}, 0);
QCOMPARE(retId, replacesId);
QCOMPARE(++proxiedNotifications, d->getSentPackets());
QVERIFY(!d->getLastPacket()->hasPayload());
// if sync not requested no payload:
plugin->config()->set(QStringLiteral("generalSynchronizeIcons"), false);
retId = listener->Notify(appName, replacesId, fi.baseName(), summary, body, {}, {{}}, 0);
QCOMPARE(retId, replacesId);
QCOMPARE(++proxiedNotifications, d->getSentPackets());
QVERIFY(!d->getLastPacket()->hasPayload());
QCOMPARE(d->getLastPacket()->payloadSize(), 0);
}
plugin->config()->set(QStringLiteral("generalSynchronizeIcons"), true);
// image-path in hints
if (iconPaths.size() > 0) {
retId = listener->Notify(appName, replacesId, iconPaths.size() > 1 ? iconPaths[1] : icon, summary, body, {}, {{QStringLiteral("image-path"), iconPaths[0]}}, 0);
QCOMPARE(retId, replacesId);
QCOMPARE(++proxiedNotifications, d->getSentPackets());
QVERIFY(d->getLastPacket()->hasPayload());
QFileInfo hintsFi(iconPaths[0]);
// image-path has priority over appIcon parameter:
QCOMPARE(d->getLastPacket()->payloadSize(), hintsFi.size());
}
// image_path in hints
if (iconPaths.size() > 0) {
retId = listener->Notify(appName, replacesId, iconPaths.size() > 1 ? iconPaths[1] : icon, summary, body, {}, {{QStringLiteral("image_path"), iconPaths[0]}}, 0);
QCOMPARE(retId, replacesId);
QCOMPARE(++proxiedNotifications, d->getSentPackets());
QVERIFY(d->getLastPacket()->hasPayload());
QFileInfo hintsFi(iconPaths[0]);
// image_path has priority over appIcon parameter:
QCOMPARE(d->getLastPacket()->payloadSize(), hintsFi.size());
}
// image-data in hints
// set up:
QBuffer* buffer;
QImage image;
int width = 2, height = 2, rowStride = 4*width, bitsPerSample = 8,
channels = 4;
bool hasAlpha = 1;
char rawData[] = { 0x01, 0x02, 0x03, 0x04, // raw rgba data
0x11, 0x12, 0x13, 0x14,
0x21, 0x22, 0x23, 0x24,
0x31, 0x32, 0x33, 0x34 };
QVariantMap imageData = {{QStringLiteral("width"), width}, {QStringLiteral("height"), height}, {QStringLiteral("rowStride"), rowStride},
{QStringLiteral("bitsPerSample"), bitsPerSample}, {QStringLiteral("channels"), channels},
{QStringLiteral("hasAlpha"), hasAlpha}, {QStringLiteral("imageData"), QByteArray(rawData, sizeof(rawData))}};
QVariantMap hints;
#define COMPARE_PIXEL(x, y) \
QCOMPARE(qRed(image.pixel(x,y)), (int)rawData[x*4 + y*rowStride + 0]); \
QCOMPARE(qGreen(image.pixel(x,y)), (int)rawData[x*4 + y*rowStride + 1]); \
QCOMPARE(qBlue(image.pixel(x,y)), (int)rawData[x*4 + y*rowStride + 2]); \
QCOMPARE(qAlpha(image.pixel(x,y)), (int)rawData[x*4 + y*rowStride + 3]);
hints.insert(QStringLiteral("image-data"), imageData);
if (iconPaths.size() > 0)
hints.insert(QStringLiteral("image-path"), iconPaths[0]);
retId = listener->Notify(appName, replacesId, icon, summary, body, {}, hints, 0);
QCOMPARE(retId, replacesId);
QCOMPARE(++proxiedNotifications, d->getSentPackets());
QVERIFY(d->getLastPacket()->hasPayload());
buffer = dynamic_cast<QBuffer*>(d->getLastPacket()->payload().data());
QCOMPARE(d->getLastPacket()->payloadSize(), buffer->size());
// image-data is attached as png data
QVERIFY(image.loadFromData(reinterpret_cast<const uchar*>(buffer->data().constData()), buffer->size(), "PNG"));
// image-data has priority over image-path:
QCOMPARE(image.sizeInBytes(), rowStride*height);
// rgba -> argb conversion was done correctly:
COMPARE_PIXEL(0,0);
COMPARE_PIXEL(1,0);
COMPARE_PIXEL(0,1);
COMPARE_PIXEL(1,1);
// same for image_data in hints
hints.clear();
hints.insert(QStringLiteral("image-data"), imageData);
if (iconPaths.size() > 0)
hints.insert(QStringLiteral("image_path"), iconPaths[0]);
retId = listener->Notify(appName, replacesId, icon, summary, body, {}, hints, 0);
QCOMPARE(retId, replacesId);
QCOMPARE(++proxiedNotifications, d->getSentPackets());
QVERIFY(d->getLastPacket()->hasPayload());
buffer = dynamic_cast<QBuffer*>(d->getLastPacket()->payload().data());
QCOMPARE(d->getLastPacket()->payloadSize(), buffer->size());
// image-data is attached as png data
QVERIFY(image.loadFromData(reinterpret_cast<const uchar*>(buffer->data().constData()), buffer->size(), "PNG"));
// image_data has priority over image_path/image-path:
QCOMPARE(image.sizeInBytes(), rowStride*height);
// rgba -> argb conversion was done correctly:
COMPARE_PIXEL(0,0);
COMPARE_PIXEL(1,0);
COMPARE_PIXEL(0,1);
COMPARE_PIXEL(1,1);
// same for icon_data, which has lowest priority
hints.clear();
hints.insert(QStringLiteral("icon_data"), imageData);
retId = listener->Notify(appName, replacesId, QLatin1String(""), summary, body, {}, hints, 0);
QCOMPARE(retId, replacesId);
QCOMPARE(++proxiedNotifications, d->getSentPackets());
QVERIFY(d->getLastPacket());
QVERIFY(d->getLastPacket()->hasPayload());
buffer = dynamic_cast<QBuffer*>(d->getLastPacket()->payload().data());
// image-data is attached as png data
QVERIFY(image.loadFromData(reinterpret_cast<const uchar*>(buffer->data().constData()), buffer->size(), "PNG"));
QCOMPARE(image.sizeInBytes(), rowStride*height);
// rgba -> argb conversion was done correctly:
COMPARE_PIXEL(0,0);
COMPARE_PIXEL(1,0);
COMPARE_PIXEL(0,1);
COMPARE_PIXEL(1,1);
#undef COMPARE_PIXEL
}
QTEST_GUILESS_MAIN(TestNotificationListener);
#include "testnotificationlistener.moc"

View file

@ -1,361 +0,0 @@
/**
* Copyright 2015 Vineet Garg <albertvaka@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License or (at your option) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 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 <https://www.gnu.org/licenses/>.
*/
#include "../core/backends/lan/server.h"
#include "../core/backends/lan/socketlinereader.h"
#include "../core/qtcompat_p.h"
#include <QSslKey>
#include <QtCrypto>
#include <QTest>
#include <QTimer>
#include <QSignalSpy>
/*
* This class tests the behaviour of socket line reader when the connection if over ssl. Since SSL takes part below application layer,
* working of SocketLineReader should be same.
*/
class TestSslSocketLineReader : public QObject
{
Q_OBJECT
public Q_SLOTS:
void newPacket();
void testTimeout();
private Q_SLOTS:
void initTestCase();
void init();
void cleanup();
void cleanupTestCase();
void testTrustedDevice();
void testUntrustedDevice();
void testTrustedDeviceWithWrongCertificate();
private:
const int PORT = 7894;
const int TIMEOUT = 4 * 1000;
QTimer m_timer;
QCA::Initializer m_qcaInitializer;
QEventLoop m_loop;
QList<QByteArray> m_packets;
Server* m_server;
QSslSocket* m_clientSocket;
SocketLineReader* m_reader;
private:
void setSocketAttributes(QSslSocket* socket, QString deviceName);
};
void TestSslSocketLineReader::initTestCase()
{
m_server = new Server(this);
QVERIFY2(m_server->listen(QHostAddress::LocalHost, PORT), "Failed to create local tcp server");
m_timer.setSingleShot(true);
connect(&m_timer, &QTimer::timeout, this, &TestSslSocketLineReader::testTimeout);
}
void TestSslSocketLineReader::init()
{
m_timer.setInterval(TIMEOUT);
m_timer.start();
m_clientSocket = new QSslSocket(this);
m_clientSocket->connectToHost(QHostAddress::LocalHost, PORT);
connect(m_clientSocket, &QAbstractSocket::connected, &m_loop, &QEventLoop::quit);
m_loop.processEvents(QEventLoop::AllEvents, TIMEOUT);
QVERIFY2(m_clientSocket->isOpen(), "Could not connect to local tcp server");
}
void TestSslSocketLineReader::cleanup()
{
m_clientSocket->disconnectFromHost();
m_timer.stop();
delete m_clientSocket;
}
void TestSslSocketLineReader::cleanupTestCase()
{
delete m_server;
}
void TestSslSocketLineReader::testTrustedDevice()
{
int maxAttemps = 5;
while(!m_server->hasPendingConnections() && maxAttemps > 0) {
--maxAttemps;
QTest::qSleep(1000);
}
QCOMPARE(true, m_server->hasPendingConnections());
QSslSocket* serverSocket = m_server->nextPendingConnection();
QSignalSpy serverEncryptedSpy(serverSocket, SIGNAL(encrypted()));
QVERIFY2(serverSocket != 0, "Null socket returned by server");
QVERIFY2(serverSocket->isOpen(), "Server socket already closed");
setSocketAttributes(serverSocket, QStringLiteral("Test Server"));
setSocketAttributes(m_clientSocket, QStringLiteral("Test Client"));
serverSocket->setPeerVerifyName(QStringLiteral("Test Client"));
serverSocket->setPeerVerifyMode(QSslSocket::VerifyPeer);
serverSocket->addCaCertificate(m_clientSocket->localCertificate());
m_clientSocket->setPeerVerifyName(QStringLiteral("Test Server"));
m_clientSocket->setPeerVerifyMode(QSslSocket::VerifyPeer);
m_clientSocket->addCaCertificate(serverSocket->localCertificate());
int connected_sockets = 0;
auto connected_lambda = [&](){
connected_sockets++;
if (connected_sockets >= 2) {
m_loop.quit();
}
};
connect(serverSocket, &QSslSocket::encrypted, connected_lambda);
connect(m_clientSocket, &QSslSocket::encrypted, connected_lambda);
serverSocket->startServerEncryption();
m_clientSocket->startClientEncryption();
m_loop.exec(); //Block until QEventLoop::quit gets called by the lambda
if (serverEncryptedSpy.count() < 1) {
for(int x = 0;x < 50; ++x) {
QVERIFY(serverEncryptedSpy.wait(100));
if (serverEncryptedSpy.count() > 0) {
break;
}
}
}
// Both client and server socket should be encrypted here and should have remote certificate because VerifyPeer is used
QVERIFY2(m_clientSocket->isOpen(), "Client socket already closed");
QVERIFY2(serverSocket->isOpen(), "Server socket already closed");
QVERIFY2(m_clientSocket->isEncrypted(), "Client is not encrypted");
QVERIFY2(serverSocket->isEncrypted(), "Server is not encrypted");
QVERIFY2(!m_clientSocket->peerCertificate().isNull(), "Server certificate not received");
QVERIFY2(!serverSocket->peerCertificate().isNull(), "Client certificate not received");
QList<QByteArray> dataToSend;
dataToSend << "foobar\n" << "barfoo\n" << "foobar?\n" << "\n" << "barfoo!\n" << "panda\n";
for (const QByteArray& line : qAsConst(dataToSend)) {
m_clientSocket->write(line);
}
m_clientSocket->flush();
m_packets.clear();
m_reader = new SocketLineReader(serverSocket, this);
connect(m_reader, &SocketLineReader::readyRead, this,&TestSslSocketLineReader::newPacket);
m_loop.exec();
/* remove the empty line before compare */
dataToSend.removeOne("\n");
QCOMPARE(m_packets.count(), 5);//We expect 5 Packets
for(int x = 0;x < 5; ++x) {
QCOMPARE(m_packets[x], dataToSend[x]);
}
delete m_reader;
}
void TestSslSocketLineReader::testUntrustedDevice()
{
int maxAttemps = 5;
while(!m_server->hasPendingConnections() && maxAttemps > 0) {
--maxAttemps;
QTest::qSleep(1000);
}
QCOMPARE(true, m_server->hasPendingConnections());
QSslSocket* serverSocket = m_server->nextPendingConnection();
QSignalSpy serverEncryptedSpy(serverSocket, SIGNAL(encrypted()));
QVERIFY2(serverSocket != 0, "Null socket returned by server");
QVERIFY2(serverSocket->isOpen(), "Server socket already closed");
setSocketAttributes(serverSocket, QStringLiteral("Test Server"));
setSocketAttributes(m_clientSocket, QStringLiteral("Test Client"));
serverSocket->setPeerVerifyName(QStringLiteral("Test Client"));
serverSocket->setPeerVerifyMode(QSslSocket::QueryPeer);
m_clientSocket->setPeerVerifyName(QStringLiteral("Test Server"));
m_clientSocket->setPeerVerifyMode(QSslSocket::QueryPeer);
int connected_sockets = 0;
auto connected_lambda = [&](){
connected_sockets++;
if (connected_sockets >= 2) {
m_loop.quit();
}
};
connect(serverSocket, &QSslSocket::encrypted, connected_lambda);
connect(m_clientSocket, &QSslSocket::encrypted, connected_lambda);
serverSocket->startServerEncryption();
m_clientSocket->startClientEncryption();
m_loop.exec(); //Block until QEventLoop::quit gets called by the lambda
if (serverEncryptedSpy.count() < 1) {
for(int x = 0;x < 50; ++x) {
QVERIFY(serverEncryptedSpy.wait(100));
if (serverEncryptedSpy.count() > 0) {
break;
}
}
}
QVERIFY2(m_clientSocket->isOpen(), "Client socket already closed");
QVERIFY2(serverSocket->isOpen(), "Server socket already closed");
QVERIFY2(m_clientSocket->isEncrypted(), "Client is not encrypted");
QVERIFY2(serverSocket->isEncrypted(), "Server is not encrypted");
QVERIFY2(!m_clientSocket->peerCertificate().isNull(), "Server certificate not received");
QVERIFY2(!serverSocket->peerCertificate().isNull(), "Client certificate not received");
QList<QByteArray> dataToSend;
dataToSend << "foobar\n" << "barfoo\n" << "foobar?\n" << "\n" << "barfoo!\n" << "panda\n";
for (const QByteArray& line : qAsConst(dataToSend)) {
m_clientSocket->write(line);
}
m_clientSocket->flush();
m_packets.clear();
m_reader = new SocketLineReader(serverSocket, this);
connect(m_reader, &SocketLineReader::readyRead, this, &TestSslSocketLineReader::newPacket);
m_loop.exec();
/* remove the empty line before compare */
dataToSend.removeOne("\n");
QCOMPARE(m_packets.count(), 5);//We expect 5 Packets
for(int x = 0;x < 5; ++x) {
QCOMPARE(m_packets[x], dataToSend[x]);
}
delete m_reader;
}
void TestSslSocketLineReader::testTrustedDeviceWithWrongCertificate()
{
int maxAttemps = 5;
while(!m_server->hasPendingConnections() && maxAttemps > 0) {
--maxAttemps;
QTest::qSleep(1000);
}
QCOMPARE(true, m_server->hasPendingConnections());
QSslSocket* serverSocket = m_server->nextPendingConnection();
QVERIFY2(serverSocket != 0, "Could not open a connection to the client");
setSocketAttributes(serverSocket, QStringLiteral("Test Server"));
setSocketAttributes(m_clientSocket, QStringLiteral("Test Client"));
// Not adding other device certificate to list of CA certificate, and using VerifyPeer. This should lead to handshake failure
serverSocket->setPeerVerifyName(QStringLiteral("Test Client"));
serverSocket->setPeerVerifyMode(QSslSocket::VerifyPeer);
m_clientSocket->setPeerVerifyName(QStringLiteral("Test Server"));
m_clientSocket->setPeerVerifyMode(QSslSocket::VerifyPeer);
connect(serverSocket, &QSslSocket::encrypted, &m_loop, &QEventLoop::quit); // Encrypted signal should never be emitted
connect(m_clientSocket, &QSslSocket::encrypted, &m_loop, &QEventLoop::quit); // Encrypted signal should never be emitted
connect(serverSocket, &QAbstractSocket::disconnected, &m_loop, &QEventLoop::quit);
connect(m_clientSocket, &QAbstractSocket::disconnected, &m_loop, &QEventLoop::quit);
serverSocket->startServerEncryption();
m_clientSocket->startClientEncryption();
m_loop.exec();
QVERIFY2(!serverSocket->isEncrypted(), "Server is encrypted, it should not");
QVERIFY2(!m_clientSocket->isEncrypted(), "lient is encrypted, it should now");
if (serverSocket->state() != QAbstractSocket::UnconnectedState) m_loop.exec(); // Wait until serverSocket is disconnected, It should be in disconnected state
if (m_clientSocket->state() != QAbstractSocket::UnconnectedState) m_loop.exec(); // Wait until mClientSocket is disconnected, It should be in disconnected state
QCOMPARE((int)m_clientSocket->state(), 0);
QCOMPARE((int)serverSocket->state(), 0);
}
void TestSslSocketLineReader::newPacket()
{
if (!m_reader->bytesAvailable()) {
return;
}
int maxLoops = 5;
while(m_reader->bytesAvailable() > 0 && maxLoops > 0) {
--maxLoops;
const QByteArray packet = m_reader->readLine();
if (!packet.isEmpty()) {
m_packets.append(packet);
}
if (m_packets.count() == 5) {
m_loop.exit();
}
}
}
void TestSslSocketLineReader::testTimeout()
{
m_loop.exit(-1);
QFAIL("Test Timed Out");
}
void TestSslSocketLineReader::setSocketAttributes(QSslSocket* socket, QString deviceName) {
QDateTime startTime = QDateTime::currentDateTime();
QDateTime endTime = startTime.addYears(10);
QCA::CertificateInfo certificateInfo;
certificateInfo.insert(QCA::CommonName,deviceName);
certificateInfo.insert(QCA::Organization,QStringLiteral("KDE"));
certificateInfo.insert(QCA::OrganizationalUnit,QStringLiteral("Kde connect"));
QCA::CertificateOptions certificateOptions(QCA::PKCS10);
certificateOptions.setSerialNumber(10);
certificateOptions.setInfo(certificateInfo);
certificateOptions.setValidityPeriod(startTime, endTime);
certificateOptions.setFormat(QCA::PKCS10);
QCA::PrivateKey privKey = QCA::KeyGenerator().createRSA(2048);
QSslCertificate certificate = QSslCertificate(QCA::Certificate(certificateOptions, privKey).toPEM().toLatin1());
socket->setPrivateKey(QSslKey(privKey.toPEM().toLatin1(), QSsl::Rsa));
socket->setLocalCertificate(certificate);
}
QTEST_GUILESS_MAIN(TestSslSocketLineReader)
#include "testsslsocketlinereader.moc"