Commit 4ff9f87b authored by Stefano Crocco's avatar Stefano Crocco

Add test to check that cookies are imported from KCookieServer at creation

In theory it should be possible to test this by connecting to
QWebEngineCookieStore::cookieAdded signal. However, in tests this signal
is not emitted (or, at least, it's emitted after the test has run). To
work around this issue, if the BUILD_TESTING cmake variable is true, a new
instance variable is created for WebEnginePartCookieJar and cookies added on
creation are stored there. The contents of this variable are then checked by

Currently, the tests fail because there's a small difference (of the
order of milliseconds, it seems) on the expiration dates. These tests
are currently marked as expected failures

Test Plan: run autotests

Reviewers: dfaure

Reviewed By: dfaure

Differential Revision:
parent 7f74ac06
......@@ -32,6 +32,26 @@
#include <QDBusInterface>
#include <QDBusReply>
#include <algorithm>
//Cookie expiration dates returned by KCookieServer always have msecs set to 0
static QDateTime currentDateTime(){return QDateTime::fromSecsSinceEpoch(QDateTime::currentMSecsSinceEpoch()/1000);}
namespace QTest {
template <>
char *toString(const QNetworkCookie &cookie){
QByteArray ba = "QNetworkCookie{";
ba += "\nname: " +;
ba += "\ndomain: " + (cookie.domain().isEmpty() ? "<EMPTY>" : cookie.domain());
ba += "\npath: " + (cookie.path().isEmpty() ? "<EMPTY>" : cookie.path());
ba += "\nvalue: " + cookie.value();
ba += "\nexpiration: " + (cookie.expirationDate().isValid() ? QString::number(cookie.expirationDate().toMSecsSinceEpoch()) : "<INVALID>");
ba += "\nsecure: " + QString::number(cookie.isSecure());
ba += "\nhttp: only" + QString::number(cookie.isHttpOnly());
return qstrdup(;
void TestWebEnginePartCookieJar::initTestCase()
......@@ -246,20 +266,9 @@ void TestWebEnginePartCookieJar::testCookieRemovedFromStoreAreRemovedFromKCookie
QFETCH(const QString, domain);
QFETCH(const QString, host);
const QString url = "https://" + host;
//cookie is in the "format" used by QWebEngineCookieStore, which means that, if the domain should be empty,
//it is stored as a domain not starting with a dot. KCookieServer, instead, wants cookies without domains
//to actually have no domain, so we have to change it
QNetworkCookie kcookieServerCookie(cookie);
if (!kcookieServerCookie.domain().startsWith('.')) {
const QByteArray setCookie = "Set-Cookie: " + kcookieServerCookie.toRawForm();
//Add cookie to KCookieServer
QDBusMessage rep = m_server->call(QDBus::Block, "addCookies", url, setCookie, static_cast<qlonglong>(0));
QVERIFY2(!m_server->lastError().isValid(), qPrintable(m_server->lastError().message()));
QDBusError e = addCookieToKCookieServer(cookie, host);
QVERIFY2(!e.isValid(), qPrintable(m_server->lastError().message()));
//Ensure cookie has been added to KCookieServer
QDBusReply<QStringList> reply = m_server->call(QDBus::Block, "findCookies", QVariant::fromValue(QList<int>{2}), domain, host, "", "");
......@@ -274,3 +283,76 @@ void TestWebEnginePartCookieJar::testCookieRemovedFromStoreAreRemovedFromKCookie
cookies = reply.value();
QVERIFY2(!cookies.contains(name), "Cookie wasn't removed from server");
QDBusError TestWebEnginePartCookieJar::addCookieToKCookieServer(const QNetworkCookie& _cookie, const QString& host)
QNetworkCookie cookie(_cookie);
QUrl url;
url.setScheme(cookie.isSecure() ? "https" : "http");
if (!cookie.domain().startsWith('.')) {
const QByteArray setCookie = "Set-Cookie: " + cookie.toRawForm();
m_server->call(QDBus::Block, "addCookies", url.toString(), setCookie, static_cast<qlonglong>(0));
return m_server->lastError();
void TestWebEnginePartCookieJar::testPersistentCookiesAreAddedToStoreOnCreation()
delete m_jar;
QDateTime exp = QDateTime::currentDateTime().addYears(1);
QString baseCookieName = m_cookieName + "-startup";
QList<CookieData> data {
{baseCookieName + "-persistent", "test-value", "", "/abc/def/", "", currentDateTime().addYears(1), true},
{baseCookieName + "-no-path", "test-value", "", "", "", currentDateTime().addYears(1), true},
{baseCookieName + "-no-domain", "test-value", "", "/abc/def/", "", currentDateTime().addYears(1), true},
{baseCookieName + "-no-secure", "test-value", "", "/abc/def/", "", currentDateTime().addYears(1), false}
QList<QNetworkCookie> expected;
for(const CookieData &d: data){
QNetworkCookie c = d.cookie();
QDBusError e = addCookieToKCookieServer(c,;
QVERIFY2(!e.isValid(), qPrintable(e.message()));
//In case of an empty domain, WebEnginePartCookieJar will use QNetworkCookie::normalize on the cookie
if (c.domain().isEmpty()) {
expected << c;
m_jar = new WebEnginePartCookieJar(m_profile, this);
QList<QNetworkCookie> cookiesInsertedIntoJar;
for(const QNetworkCookie &c: qAsConst(m_jar->m_testCookies)){
if(QString( {
cookiesInsertedIntoJar << c;
//Ensure that cookies in the two lists are in the same order before comparing them
//(the order in cookiesInsertedIntoJar depends on the order KCookieServer::findCookies
//returns them)
auto sortLambda = [](const QNetworkCookie &c1, const QNetworkCookie &c2){
return <;
std::sort(cookiesInsertedIntoJar.begin(), cookiesInsertedIntoJar.end(), sortLambda);
std::sort(expected.begin(), expected.end(), sortLambda);
QCOMPARE(cookiesInsertedIntoJar, expected);
void TestWebEnginePartCookieJar::testSessionCookiesAreNotAddedToStoreOnCreation()
delete m_jar;
CookieData data{m_cookieName + "-startup-session", "test-value", "", "/abc/def", "", QDateTime(), true};
QDBusError e = addCookieToKCookieServer(data.cookie(),;
QVERIFY2(!e.isValid(), qPrintable(e.message()));
m_jar = new WebEnginePartCookieJar(m_profile, this);
QList<QNetworkCookie> cookiesInsertedIntoJar;
for(const QNetworkCookie &c: qAsConst(m_jar->m_testCookies)) {
if ( == {
cookiesInsertedIntoJar << c;
QVERIFY2(cookiesInsertedIntoJar.isEmpty(), "Session cookies inserted into cookie store");
......@@ -26,6 +26,7 @@
#include <QObject>
#include <QDateTime>
#include <QDBusError>
class QWebEngineCookieStore;
class WebEnginePartCookieJar;
......@@ -60,13 +61,27 @@ private Q_SLOTS:
void testCookieAddedToStoreAreAddedToKCookieServer();
void testCookieRemovedFromStoreAreRemovedFromKCookieServer_data();
void testCookieRemovedFromStoreAreRemovedFromKCookieServer();
void testPersistentCookiesAreAddedToStoreOnCreation();
void testSessionCookiesAreNotAddedToStoreOnCreation();
* @brief Adds a cookie to KCookieServer
* The cookie is supposed to be in `QWebEngineStore` "format", that is its domain must not be empty;
* a domain not starting with a dot means that the domain field wasn't given in the `Set-Cookie` header.
* @param _cookie the cookie to add
* @param host the host where the cookie come from
* @return QDBusError the error returned by DBus when adding the cookie. If no error occurred, this object
* will be invalid
QDBusError addCookieToKCookieServer(const QNetworkCookie &_cookie, const QString &host);
void deleteCookies(const QList<CookieData> &cookies);
QList<CookieData> findTestCookies();
QString m_cookieName;
QString m_cookieName;
QWebEngineCookieStore *m_store;
WebEnginePartCookieJar *m_jar;
QWebEngineProfile *m_profile;
......@@ -2,6 +2,10 @@ find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS Wallet)
......@@ -67,6 +67,7 @@ WebEnginePartCookieJar::WebEnginePartCookieJar(QWebEngineProfile *prof, QObject
qCDebug(WEBENGINEPART_LOG) << "Couldn't connect to KCookieServer";
//QWebEngineCookieStore::setCookieFilter only exists from Qt 5.11.0
......@@ -145,6 +146,10 @@ void WebEnginePartCookieJar::addCookie(const QNetworkCookie& _cookie)
QNetworkCookie cookie(_cookie);
CookieIdentifier id(cookie);
......@@ -288,6 +293,9 @@ void WebEnginePartCookieJar::loadKIOCookies()
m_cookiesLoadedFromKCookieServer << cookie;
m_testCookies << cookie;
......@@ -328,6 +328,11 @@ private:
CookieList m_cookiesLoadedFromKCookieServer;
QList<QNetworkCookie> m_testCookies;
friend class TestWebEnginePartCookieJar;
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