[Merge] lp:~abreu-alexandre/webbrowser-app/add-uninstall-click-hook-to-webapps into lp:webbrowser-app
Alberto Mardegan
alberto.mardegan at canonical.com
Wed Nov 19 07:36:00 UTC 2014
Review: Needs Information
I've added 3 inline comments, but overall the code looks solid. I would still prefer to get rid of the Fallible thing and just use the default values for the when the hook file is not present, but it's just my personal preference.
One very important thing to keep an eye on is bug 1358294, which seems to make all of this feature meaningless: before landing this we should clarify the situation, because if the data is going to be cleared no matter what, we definitely don't want to have this code in.
Diff comments:
> === modified file 'CMakeLists.txt'
> --- CMakeLists.txt 2014-10-03 14:41:26 +0000
> +++ CMakeLists.txt 2014-11-18 15:34:53 +0000
> @@ -75,3 +75,5 @@
>
> install(FILES webbrowser-app.png screenshot.png
> DESTINATION ${CMAKE_INSTALL_DATADIR}/webbrowser-app)
> +
> +add_subdirectory(click-hooks)
>
> === added directory 'click-hooks'
> === added file 'click-hooks/CMakeLists.txt'
> --- click-hooks/CMakeLists.txt 1970-01-01 00:00:00 +0000
> +++ click-hooks/CMakeLists.txt 2014-11-18 15:34:53 +0000
> @@ -0,0 +1,34 @@
> +project(webapp-container-hook)
> +
> +include_directories(
> + ${CMAKE_BINARY_DIR}
> + ${webbrowser-common_SOURCE_DIR}
> + ${webbrowser-common_BINARY_DIR}
> +)
> +
> +set(WEBAPP_CONTAINER_HOOK_FOLDER webapp-container)
> +
> +set(WEBAPP_CONTAINER_HOOK webapp-container-hook)
> +
> +add_definitions(-DWEBAPP_CONTAINER_HOOK_FOLDER="${WEBAPP_CONTAINER_HOOK_FOLDER}")
> +
> +set(WEBAPP_CONTAINER_HOOK_SRC
> + hook.cpp
> + hook-utils.h
> + hook-utils.cpp
> +)
> +
> +add_executable(${WEBAPP_CONTAINER_HOOK} ${WEBAPP_CONTAINER_HOOK_SRC})
> +
> +qt5_use_modules(${WEBAPP_CONTAINER_HOOK} Core)
> +
> +install(TARGETS ${WEBAPP_CONTAINER_HOOK}
> + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
> +
> +configure_file(
> + webapp-container.hook.in
> + ${CMAKE_CURRENT_BINARY_DIR}/webapp-container.hook
> + @ONLY)
> +
> +file(GLOB WEBAPP_CONTANER_HOOK_FILES ${CMAKE_CURRENT_BINARY_DIR}/*.hook)
> +install(FILES ${WEBAPP_CONTANER_HOOK_FILES} DESTINATION ${CMAKE_INSTALL_DATADIR}/click/hooks)
>
> === added file 'click-hooks/hook-utils.cpp'
> --- click-hooks/hook-utils.cpp 1970-01-01 00:00:00 +0000
> +++ click-hooks/hook-utils.cpp 2014-11-18 15:34:53 +0000
> @@ -0,0 +1,308 @@
> +/*
> + * Copyright 2014 Canonical Ltd.
> + *
> + * This file is part of webbrowser-app.
> + *
> + * webbrowser-app 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; version 3.
> + *
> + * webbrowser-app 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 <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "hook-utils.h"
> +
> +#include <QDateTime>
> +#include <QDebug>
> +#include <QFileInfo>
> +#include <QJsonArray>
> +#include <QJsonDocument>
> +#include <QJsonObject>
> +#include <QStandardPaths>
> +
> +
> +namespace {
> +
> +QString shortAppIdFromUnversionedAppId(const QString& appId)
> +{
> + QStringList components = appId.split('_');
> + components.removeLast();
> + return components.join('_');
> +}
> +
> +}
> +
> +
> +namespace HookUtils {
> +
> +
> +WebappHookParser::OptionalData
> +WebappHookParser::parseContent(const QString& filename)
> +{
> + QFileInfo info(filename);
> + if (!info.exists() || !info.isFile() || !info.isReadable())
> + {
> + return OptionalData(Data(), false);
> + }
> +
> + QFile file(filename);
> + if (!file.open(QIODevice::ReadOnly))
> + {
> + qWarning() << "Cannot open webapp hook: " << filename;
> + return OptionalData(Data(), false);
> + }
> +
> + QJsonDocument document(QJsonDocument::fromJson(file.readAll()));
> + if (document.isNull() || document.isEmpty() || !document.isArray()) {
> + return OptionalData(Data(), false);
> + }
> +
> + return parseDocument(document.array());
> +}
> +
> +WebappHookParser::OptionalData
> +WebappHookParser::parseDocument(const QJsonArray& array)
> +{
> + Data result;
> + if (array.count() == 0
> + || !array.at(0).isObject())
> + {
> + return OptionalData(result);
> + }
> +
> + QJsonObject rootObject = array.at(0).toObject();
> +
> +#define JSON_OBJECT_VALIDATE(o,key,predicate) \
> + o.contains(key) && o.value(key).predicate()
> +
> + const QString UNINSTALL_KEY = "uninstall";
> + if (JSON_OBJECT_VALIDATE(rootObject,UNINSTALL_KEY,isObject))
> + {
> + const QString UNINSTALL_DELETE_COOKIES = "delete-cookies";
> + const QString UNINSTALL_DELETE_CACHE = "delete-cache";
> +
> + QJsonObject uninstallObject =
> + rootObject.value(UNINSTALL_KEY).toObject();
> + if (JSON_OBJECT_VALIDATE(uninstallObject,UNINSTALL_DELETE_COOKIES,isBool))
> + {
> + result.shouldDeleteCookiesOnUninstall =
> + uninstallObject.value(UNINSTALL_DELETE_COOKIES).toBool();
> + }
> +
> + if (JSON_OBJECT_VALIDATE(uninstallObject,UNINSTALL_DELETE_CACHE,isBool))
> + {
> + result.shouldDeleteCacheOnUninstall =
> + uninstallObject.value(UNINSTALL_DELETE_CACHE).toBool();
> + }
> + }
> +#undef JSON_OBJECT_VALIDATE
> +
> + return OptionalData(result);
> +}
> +
> +WebappClickHookInstallDescription
> +listWebappProcessedClickHookFilesIn(const QDir& dir)
> +{
> + WebappClickHookInstallDescription
> + description(dir.absolutePath(), QHash<QString, QString>());
> +
> + Q_FOREACH(const QFileInfo& fileInfo, dir.entryInfoList())
> + {
> + if (fileInfo.isFile())
> + {
> + QString filename = fileInfo.fileName();
> + description.hookFiles[filename] = filename;
> + }
> + }
> + return description;
> +}
> +
> +WebappClickHookInstallDescription
> +listWebappInstalledClickHookFilesIn(const QDir& dir)
> +{
> + WebappClickHookInstallDescription
> + description(dir.absolutePath(), QHash<QString, QString>());
> +
> + const QString WEBAPP_CLICK_HOOK_FILE_EXT = "webapp";
> + Q_FOREACH(const QFileInfo& fileInfo, dir.entryInfoList())
> + {
> + if (fileInfo.isSymLink()
> + && fileInfo.symLinkTarget().endsWith(QString(".") + WEBAPP_CLICK_HOOK_FILE_EXT))
> + {
> + description.hookFiles[removeVersionFrom(fileInfo.completeBaseName())] =
> + fileInfo.fileName();
> + }
> + else if (fileInfo.suffix() == WEBAPP_CLICK_HOOK_FILE_EXT)
Can this actually ever happen? Your click hook pattern won't generate such files.
Also I find it a bit strange that both branches of this "if {} else if {}" have the same content.
Maybe you could modify your hook pattern to create the symlinks with a ".webapp" suffix, so the code here would be simpler (you'd just check for the suffix, ignoring whether the file is a symlink)?
> + {
> + description.hookFiles[removeVersionFrom(fileInfo.completeBaseName())] =
> + fileInfo.fileName();
> + }
> + }
> + return description;
> +}
> +
> +QString
> +getProcessedClickHooksFolder()
> +{
> + QString result = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation)
> + + "/webapp-container";
> + if (!qgetenv("WEBAPPCONTAINER_PROCESSED_HOOKS_FOLDER").isNull())
> + {
> + result = QString(qgetenv("WEBAPPCONTAINER_PROCESSED_HOOKS_FOLDER"));
> + }
> + return result;
> +}
> +
> +QString
> +getClickHooksInstallFolder()
> +{
> + QString result = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)
> + + "/webapp-container";
> + if (!qgetenv("WEBAPPCONTAINER_INSTALLED_HOOKS_FOLDER").isNull())
> + {
> + result = QString(qgetenv("WEBAPPCONTAINER_INSTALLED_HOOKS_FOLDER"));
> + }
> + return result;
> +}
> +
> +QString removeVersionFrom(const QString& appId)
> +{
> + QStringList components = appId.split('_');
> + if (components.count() != 3)
> + {
> + return appId;
> + }
> + components.removeLast();
> + return components.join('_');
> +}
> +
> +void handleInstalls(const WebappClickHookInstallDescription& alreadyProcessedClickHooks
> + , const WebappClickHookInstallDescription& installedClickHooks)
> +{
> + QStringList newlyInstalledClickPackages =
> + installedClickHooks.hookFiles.keys().toSet().subtract(
> + alreadyProcessedClickHooks.hookFiles.keys().toSet()).toList();
> +
> + if (newlyInstalledClickPackages.count() == 0)
I prefer isEmpty(), but I won't block the review on this :-p
> + {
> + qDebug() << "Nothing to install.";
> + return;
> + }
> +
> + Q_FOREACH(const QString& webappClickHook, newlyInstalledClickPackages)
> + {
> + QString hookFilename =
> + installedClickHooks.parentFolder + "/"
> + + installedClickHooks.hookFiles[webappClickHook];
> +
> + QFileInfo hookFileInfo(hookFilename);
> + QString appIdNoVersion = removeVersionFrom(hookFileInfo.completeBaseName());
> +
> + QString destination = QString("%1/%2").
> + arg(alreadyProcessedClickHooks.parentFolder).arg(appIdNoVersion);
> +
> + qDebug() << "Installing: " << destination;
> +
> + QFile::copy(hookFilename, destination);
> + }
> +
> +}
> +
> +void handleUninstall(const WebappClickHookInstallDescription& alreadyProcessedClickHooks
> + , const WebappClickHookInstallDescription& currentClickHooks)
> +{
> + WebappHookParser webappHookParser;
> + QStringList deletedClickPackages =
> + alreadyProcessedClickHooks.hookFiles.keys().toSet().subtract(
> + currentClickHooks.hookFiles.keys().toSet()).toList();
> +
> + if (deletedClickPackages.count() == 0)
> + {
> + qDebug() << "Nothing to delete.";
> + return;
> + }
> +
> + Q_FOREACH(const QString& webappClickHook, deletedClickPackages)
> + {
> + QString hookFilename =
> + alreadyProcessedClickHooks.parentFolder + "/" + webappClickHook;
> +
> + WebappHookParser::OptionalData optional_data =
> + webappHookParser.parseContent(hookFilename);
> + if (!optional_data.is_valid())
> + {
> + continue;
> + }
> +
> + QFileInfo fileInfo(hookFilename);
> + QString appIdNoVersion = fileInfo.fileName();
> +
> + WebappHookParser::Data data = optional_data.value();
> + if (data.shouldDeleteCacheOnUninstall)
> + {
> + QDir dir(QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation)
> + + "/" + shortAppIdFromUnversionedAppId(appIdNoVersion));
> + dir.removeRecursively();
> + }
> + if (data.shouldDeleteCookiesOnUninstall)
> + {
> + QDir dir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)
> + + "/" + shortAppIdFromUnversionedAppId(appIdNoVersion));
> + dir.removeRecursively();
> + }
> +
> + qDebug() << "Uninstalling: " << hookFilename;
> +
> + QFile::remove(hookFilename);
> + }
> +}
> +
> +void handleUpdates(const WebappClickHookInstallDescription& alreadyProcessedClickHooks
> + , const WebappClickHookInstallDescription& installedClickHooks)
> +{
> + QStringList foundClickHooks =
> + alreadyProcessedClickHooks.hookFiles.keys().toSet().intersect(
> + installedClickHooks.hookFiles.keys().toSet()).toList();
> + if (foundClickHooks.count() == 0)
> + {
> + qDebug() << "Nothing to update.";
> + return;
> + }
> +
> + Q_FOREACH(const QString& webappClickHook, foundClickHooks)
> + {
> + QString hookFilename =
> + installedClickHooks.parentFolder + "/"
> + + installedClickHooks.hookFiles[webappClickHook];
> +
> + QFileInfo hookFileInfo(hookFilename);
> + QString appIdNoVersion = removeVersionFrom(hookFileInfo.completeBaseName());
> +
> + QString destination = QString("%1/%2").
> + arg(alreadyProcessedClickHooks.parentFolder).arg(appIdNoVersion);
> +
> + QFileInfo destinationInfo(destination);
> + if (destinationInfo.exists() &&
> + destinationInfo.lastModified() >= hookFileInfo.lastModified()) {
> + continue;
> + }
> +
> + qDebug() << "Updating " << destination;
> +
> + if (QFile::exists(destination))
> + {
> + QFile::remove(destination);
> + }
> +
> + QFile::copy(hookFilename, destination);
> + }
> +}
> +
> +
> +}
>
> === added file 'click-hooks/hook-utils.h'
> --- click-hooks/hook-utils.h 1970-01-01 00:00:00 +0000
> +++ click-hooks/hook-utils.h 2014-11-18 15:34:53 +0000
> @@ -0,0 +1,147 @@
> +/*
> + * Copyright 2014 Canonical Ltd.
> + *
> + * This file is part of webbrowser-app.
> + *
> + * webbrowser-app 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; version 3.
> + *
> + * webbrowser-app 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 <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <QDir>
> +#include <QHash>
> +#include <QString>
> +#include <QStringList>
> +#include <exception>
> +
> +
> +namespace HookUtils {
> +
> +/**
> + * Simple optional type wrapper
> + */
> +template <typename T>
> +class Fallible
> +{
> +public:
> + explicit Fallible<T>(const T& data, bool is_valid = true)
> + : _data(data), _is_valid(is_valid) {}
> +
> + bool is_valid() const { return _is_valid; }
> + const T& value() const
> + {
> + if (!is_valid())
> + {
> + throw std::exception();
> + }
> + return _data;
> + }
> +
> +private:
> + T _data;
> + bool _is_valid;
> +};
> +
> +/**
> + * @brief The WebappHookParser class
> + */
> +class WebappHookParser {
> +public:
> + struct Data
> + {
> + Data ()
> + : shouldDeleteCacheOnUninstall(false)
> + , shouldDeleteCookiesOnUninstall(false) {}
> + bool shouldDeleteCacheOnUninstall;
> + bool shouldDeleteCookiesOnUninstall;
> + };
> + typedef Fallible<Data> OptionalData;
> +
> +public:
> + OptionalData parseContent(const QString& filename);
> +private:
> + OptionalData parseDocument(const QJsonArray& array);
> +};
> +
> +/**
> + * @brief Simple POD for click hook files & their parent folders.
> + */
> +struct WebappClickHookInstallDescription
> +{
> + WebappClickHookInstallDescription(
> + const QString& folder,
> + const QHash<QString, QString>& files)
> + : parentFolder(folder), hookFiles(files) {}
> +
> + QString parentFolder;
> + QHash<QString, QString> hookFiles;
> +};
> +
> +/**
> + * @brief listWebappProcessedClickHookFilesIn
> + * @param dir
> + * @return
> + */
> +WebappClickHookInstallDescription
> +listWebappProcessedClickHookFilesIn(const QDir& dir);
> +
> +/**
> + * @brief listWebappInstalledClickHookFilesIn
> + * @param dir
> + * @return
> + */
> +WebappClickHookInstallDescription
> +listWebappInstalledClickHookFilesIn(const QDir& dir);
> +
> +/**
> + * @brief getProcessedClickHooksFolder
> + * @return
> + */
> +QString getProcessedClickHooksFolder();
> +
> +/**
> + * @brief getClickHooksInstallFolder
> + * @return
> + */
> +QString getClickHooksInstallFolder();
> +
> +/**
> + * @brief removeVersionFrom
> + * @param appId
> + * @return
> + */
> +QString removeVersionFrom(const QString& appId);
> +
> +/**
> + * @brief handleInstalls Detects click package uninstalls and handled what's needed
> + * @param alreadyProcessedClickHooks
> + * @param currentClickHooks
> + */
> +void handleInstalls(const WebappClickHookInstallDescription& alreadyProcessedClickHooks
> + , const WebappClickHookInstallDescription& currentClickHooks);
> +
> +/**
> + * @brief handleUninstall Detects click package uninstalls and handled what's needed
> + * @param alreadyProcessedClickHooks
> + * @param currentClickHooks
> + */
> +void handleUninstall(const WebappClickHookInstallDescription& alreadyProcessedClickHooks
> + , const WebappClickHookInstallDescription& currentClickHooks);
> +
> +/**
> + * @brief handleUpdates
> + * @param alreadyProcessedClickHooks
> + * @param currentClickHooks
> + */
> +void handleUpdates(const WebappClickHookInstallDescription& alreadyProcessedClickHooks
> + , const WebappClickHookInstallDescription& installedClickHooks);
> +
> +} // namespace HookUtils
>
> === added file 'click-hooks/hook.cpp'
> --- click-hooks/hook.cpp 1970-01-01 00:00:00 +0000
> +++ click-hooks/hook.cpp 2014-11-18 15:34:53 +0000
> @@ -0,0 +1,67 @@
> +/*
> + * Copyright 2014 Canonical Ltd.
> + *
> + * This file is part of webbrowser-app.
> + *
> + * webbrowser-app 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; version 3.
> + *
> + * webbrowser-app 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 <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <QCoreApplication>
> +#include <QDebug>
> +#include <QDir>
> +#include <QFileInfo>
> +#include <QStandardPaths>
> +#include <QString>
> +
> +#include "hook-utils.h"
> +
> +
> +int main(int argc, char ** argv)
> +{
> + QCoreApplication app(argc, argv);
> +
> + if (app.arguments().count() != 1)
> + {
> + qWarning() << "Invalid hook argument count";
> + return EXIT_FAILURE;
> + }
> +
> + QString processedClickHooksFolder =
> + HookUtils::getProcessedClickHooksFolder();
> + if (!QDir(processedClickHooksFolder).exists())
> + {
> + QDir().mkdir(processedClickHooksFolder);
mkpath() also creates parent directories as needed, so I'd recommend using that instead.
> + }
> +
> + HookUtils::WebappClickHookInstallDescription alreadyProcessedClickHooks =
> + HookUtils::listWebappProcessedClickHookFilesIn(
> + processedClickHooksFolder);
> +
> + HookUtils::WebappClickHookInstallDescription installedClickHooks =
> + HookUtils::listWebappInstalledClickHookFilesIn(
> + HookUtils::getClickHooksInstallFolder());
> +
> + HookUtils::handleInstalls(
> + alreadyProcessedClickHooks,
> + installedClickHooks);
> +
> + HookUtils::handleUpdates(
> + alreadyProcessedClickHooks,
> + installedClickHooks);
> +
> + HookUtils::handleUninstall(
> + alreadyProcessedClickHooks,
> + installedClickHooks);
> +
> + return EXIT_SUCCESS;
> +}
>
> === added file 'click-hooks/webapp-container.hook.in'
> --- click-hooks/webapp-container.hook.in 1970-01-01 00:00:00 +0000
> +++ click-hooks/webapp-container.hook.in 2014-11-18 15:34:53 +0000
> @@ -0,0 +1,3 @@
> +Pattern: ${home}/.local/share/@WEBAPP_CONTAINER_HOOK_FOLDER@/${id}
> +Exec: @CMAKE_INSTALL_FULL_BINDIR@/@WEBAPP_CONTAINER_HOOK@
> +User-Level: yes
>
> === modified file 'debian/webapp-container.install'
> --- debian/webapp-container.install 2013-11-27 15:35:20 +0000
> +++ debian/webapp-container.install 2014-11-18 15:34:53 +0000
> @@ -1,2 +1,4 @@
> usr/bin/webapp-container
> usr/share/webbrowser-app/webcontainer/
> +usr/share/click/hooks/webapp-container.hook
> +usr/bin/webapp-container-hook
>
> === modified file 'tests/unittests/CMakeLists.txt'
> --- tests/unittests/CMakeLists.txt 2014-11-12 12:03:20 +0000
> +++ tests/unittests/CMakeLists.txt 2014-11-18 15:34:53 +0000
> @@ -17,3 +17,4 @@
> add_subdirectory(oxide-cookie-helper)
> add_subdirectory(session-storage)
> add_subdirectory(favicon-image-provider)
> +add_subdirectory(webapp-container-hook)
>
> === added directory 'tests/unittests/webapp-container-hook'
> === added file 'tests/unittests/webapp-container-hook/CMakeLists.txt'
> --- tests/unittests/webapp-container-hook/CMakeLists.txt 1970-01-01 00:00:00 +0000
> +++ tests/unittests/webapp-container-hook/CMakeLists.txt 2014-11-18 15:34:53 +0000
> @@ -0,0 +1,11 @@
> +set(TEST tst_WebappContainerHookTests)
> +set(SOURCES
> + ${CMAKE_SOURCE_DIR}/click-hooks/hook-utils.cpp
> + tst_WebappContainerHookTests.cpp
> +)
> +set(WEBAPP_CONTAINER_HOOK webapp-container-hook)
> +include_directories(${CMAKE_SOURCE_DIR})
> +add_definitions(-DCLICK_HOOK_EXEC_BIN="${CMAKE_BINARY_DIR}/click-hooks/${WEBAPP_CONTAINER_HOOK}")
> +add_executable(${TEST} ${SOURCES})
> +qt5_use_modules(${TEST} Core Test)
> +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
>
> === added file 'tests/unittests/webapp-container-hook/tst_WebappContainerHookTests.cpp'
> --- tests/unittests/webapp-container-hook/tst_WebappContainerHookTests.cpp 1970-01-01 00:00:00 +0000
> +++ tests/unittests/webapp-container-hook/tst_WebappContainerHookTests.cpp 2014-11-18 15:34:53 +0000
> @@ -0,0 +1,215 @@
> +/*
> + * Copyright 2014 Canonical Ltd.
> + *
> + * This file is part of webbrowser-app.
> + *
> + * webbrowser-app 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; version 3.
> + *
> + * webbrowser-app 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 <http://www.gnu.org/licenses/>.
> + */
> +
> +// Qt
> +#include <QTemporaryDir>
> +#include <QProcess>
> +#include <QtTest/QtTest>
> +
> +// local
> +#include "click-hooks/hook-utils.h"
> +
> +
> +namespace {
> +
> + void createFileWithContent(const QString& filename, const QString& content)
> + {
> + QFile file(filename);
> + if (!file.open(QIODevice::ReadWrite))
> + {
> + return;
> + }
> + file.write(content.toUtf8());
> + file.flush();
> + }
> +
> + QString readAll(const QString& filename)
> + {
> + QFile file(filename);
> + if (!file.open(QIODevice::ReadOnly))
> + {
> + return QString();
> + }
> + return file.readAll();
> + }
> +
> +}
> +
> +class WebappContainerHookTests : public QObject
> +{
> + Q_OBJECT
> +
> +private Q_SLOTS:
> +
> + void testRemoveVersion_data()
> + {
> + QTest::addColumn<QString>("appId");
> + QTest::addColumn<QString>("appIdNoVersion");
> + QTest::newRow("With version") << QString("com.ubuntu.blabla_blabla_0.2") << QString("com.ubuntu.blabla_blabla");
> + QTest::newRow("With no version") << QString("com.ubuntu.blabla_blabla") << QString("com.ubuntu.blabla_blabla");
> + }
> + void testRemoveVersion()
> + {
> + QFETCH(QString, appId);
> + QFETCH(QString, appIdNoVersion);
> + QCOMPARE(HookUtils::removeVersionFrom(appId), appIdNoVersion);
> + }
> +
> + void testClickHookUpdate_data()
> + {
> + QTest::addColumn<QString>("processedHookFilename");
> + QTest::addColumn<QString>("processedHookFileContent");
> + QTest::addColumn<QString>("installedHookFilename");
> + QTest::addColumn<QString>("installedHookFileContent");
> + QTest::addColumn<bool>("shouldBeUpdated");
> +
> + QTest::newRow("Valid hook file") << QString("com.ubuntu.blabla_blabla")
> + << QString("[{}]")
> + << QString("com.ubuntu.blabla_blabla_0.2.webapp")
> + << QString("[{\"uninstall\": { \"delete-cookies\": true, \"delete-cache\": true } }]")
> + << true;
> + QTest::newRow("Valid hook file - no update") << QString("com.ubuntu.blabla_blabla")
> + << QString("[{}]")
> + << QString("com.ubuntu.blabla_blabla_0.2.webapp")
> + << QString("[{\"uninstall\": { \"delete-cookies\": true, \"delete-cache\": true } }]")
> + << false;
> + }
> + void testClickHookUpdate()
> + {
> + QFETCH(QString, processedHookFilename);
> + QFETCH(QString, installedHookFilename);
> +
> + QFETCH(QString, processedHookFileContent);
> + QFETCH(QString, installedHookFileContent);
> +
> + QFETCH(bool, shouldBeUpdated);
> +
> + QTemporaryDir processedHookFiledTmpDir;
> + QTemporaryDir installedHookFiledTmpDir;
> +
> + QVERIFY(!processedHookFilename.isEmpty());
> + QString processedFilepath =
> + processedHookFiledTmpDir.path() + "/" + processedHookFilename;
> +
> + QVERIFY(!installedHookFilename.isEmpty());
> + QString installedHookFilepath =
> + installedHookFiledTmpDir.path() + "/" + installedHookFilename;
> +
> + if (shouldBeUpdated)
> + {
> + createFileWithContent(processedFilepath, processedHookFileContent);
> +
> + // Wait in order to have a meaningful lastModifiedData for comparaison
> + QTest::qSleep(1000);
> +
> + createFileWithContent(installedHookFilepath, installedHookFileContent);
> + }
> + else
> + {
> + createFileWithContent(installedHookFilepath, installedHookFileContent);
> +
> + // Wait in order to have a meaningful lastModifiedData for comparaison
> + QTest::qSleep(1000);
> +
> + createFileWithContent(processedFilepath, processedHookFileContent);
> + }
> +
> + QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
> + env.insert("WEBAPPCONTAINER_PROCESSED_HOOKS_FOLDER", processedHookFiledTmpDir.path());
> + env.insert("WEBAPPCONTAINER_INSTALLED_HOOKS_FOLDER", installedHookFiledTmpDir.path());
> +
> + QProcess process;
> + process.setProcessEnvironment(env);
> + process.start(CLICK_HOOK_EXEC_BIN, QStringList());
> + process.waitForFinished();
> +
> + if (shouldBeUpdated)
> + {
> + QCOMPARE(readAll(processedFilepath), readAll(installedHookFilepath));
> + }
> + else
> + {
> + QCOMPARE(readAll(processedFilepath), processedHookFileContent);
> + }
> + }
> +
> + void testClickHookInstall()
> + {
> + QString processedHookFilename =
> + "com.ubuntu.blabla_blabla";
> + QString installedHookFilename =
> + "com.ubuntu.blabla_blabla_0.2.webapp";
> + QString installedHookFileContent =
> + "[{\"uninstall\": { \"delete-cookies\": true, \"delete-cache\": true } }]";
> +
> + QTemporaryDir processedHookFiledTmpDir;
> + QTemporaryDir installedHookFiledTmpDir;
> +
> + QString processedFilepath =
> + processedHookFiledTmpDir.path() + "/" + processedHookFilename;
> + QString installedHookFilepath =
> + installedHookFiledTmpDir.path() + "/" + installedHookFilename;
> +
> + createFileWithContent(installedHookFilepath, installedHookFileContent);
> +
> + QVERIFY(!QFile::exists(processedFilepath));
> + QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
> +
> + env.insert("WEBAPPCONTAINER_PROCESSED_HOOKS_FOLDER", processedHookFiledTmpDir.path());
> + env.insert("WEBAPPCONTAINER_INSTALLED_HOOKS_FOLDER", installedHookFiledTmpDir.path());
> +
> + QProcess process;
> + process.setProcessEnvironment(env);
> + process.start(CLICK_HOOK_EXEC_BIN, QStringList());
> + process.waitForFinished();
> +
> + QVERIFY(QFile::exists(processedFilepath));
> + QCOMPARE(readAll(processedFilepath), readAll(installedHookFilepath));
> + }
> +
> + void testClickHookUninstall()
> + {
> + QString processedHookFilename =
> + "com.ubuntu.blabla_blabla";
> + QString processedHookFileContent =
> + "[{\"uninstall\": { \"delete-cookies\": false, \"delete-cache\": false } }]";
> +
> + QTemporaryDir processedHookFiledTmpDir;
> + QTemporaryDir installedHookFiledTmpDir;
> +
> + QString processedFilepath =
> + processedHookFiledTmpDir.path() + "/" + processedHookFilename;
> +
> + createFileWithContent(processedFilepath, processedHookFileContent);
> +
> + QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
> +
> + env.insert("WEBAPPCONTAINER_PROCESSED_HOOKS_FOLDER", processedHookFiledTmpDir.path());
> + env.insert("WEBAPPCONTAINER_INSTALLED_HOOKS_FOLDER", installedHookFiledTmpDir.path());
> +
> + QProcess process;
> + process.setProcessEnvironment(env);
> + process.start(CLICK_HOOK_EXEC_BIN, QStringList());
> + process.waitForFinished();
> +
> + QVERIFY(!QFile::exists(processedFilepath));
> + }
> +};
> +
> +QTEST_MAIN(WebappContainerHookTests)
> +#include "tst_WebappContainerHookTests.moc"
>
--
https://code.launchpad.net/~abreu-alexandre/webbrowser-app/add-uninstall-click-hook-to-webapps/+merge/241584
Your team Ubuntu Phablet Team is subscribed to branch lp:webbrowser-app.
More information about the Ubuntu-reviews
mailing list