test: add identify test
fix some bugs found in testing Signed-off-by: ComixHe <heyuming@deepin.org>
This commit is contained in:
parent
de09f3dbc2
commit
a3dd315e33
@ -4,7 +4,7 @@ Upstream-Contact: UnionTech Software Technology Co., Ltd. <>
|
|||||||
Source: https://github.com/linuxdeepin/dde-application-manager
|
Source: https://github.com/linuxdeepin/dde-application-manager
|
||||||
|
|
||||||
# README & DOC
|
# README & DOC
|
||||||
Files: README.md README.zh_CN.md docs/*
|
Files: README.md README.zh_CN.md docs/* examples/launchApp/README.md
|
||||||
Copyright: UnionTech Software Technology Co., Ltd.
|
Copyright: UnionTech Software Technology Co., Ltd.
|
||||||
License: CC-BY-4.0
|
License: CC-BY-4.0
|
||||||
|
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include "constant.h"
|
#include "constant.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
enum class ExitCode { SystemdError = -3, InvalidInput = -2, InternalError = -1, Done = 0, Waiting = 1 };
|
enum class ExitCode { SystemdError = -3, InvalidInput = -2, InternalError = -1, Done = 0, Waiting = 1 };
|
||||||
|
|
||||||
struct JobRemoveResult
|
struct JobRemoveResult
|
||||||
@ -29,7 +31,7 @@ struct JobRemoveResult
|
|||||||
using msg_ptr = sd_bus_message *;
|
using msg_ptr = sd_bus_message *;
|
||||||
using bus_ptr = sd_bus *;
|
using bus_ptr = sd_bus *;
|
||||||
|
|
||||||
static ExitCode fromString(const std::string &str)
|
ExitCode fromString(const std::string &str)
|
||||||
{
|
{
|
||||||
if (str == "done") {
|
if (str == "done") {
|
||||||
return ExitCode::Done;
|
return ExitCode::Done;
|
||||||
@ -50,7 +52,7 @@ static ExitCode fromString(const std::string &str)
|
|||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
static ExitCode fromString(const char *str)
|
ExitCode fromString(const char *str)
|
||||||
{
|
{
|
||||||
if (!str) {
|
if (!str) {
|
||||||
return ExitCode::Waiting;
|
return ExitCode::Waiting;
|
||||||
@ -59,7 +61,7 @@ static ExitCode fromString(const char *str)
|
|||||||
return fromString(tmp);
|
return fromString(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]] static void releaseRes(sd_bus_error &error, msg_ptr &msg, bus_ptr &bus, ExitCode ret)
|
[[noreturn]] void releaseRes(sd_bus_error &error, msg_ptr &msg, bus_ptr &bus, ExitCode ret)
|
||||||
{
|
{
|
||||||
sd_bus_error_free(&error);
|
sd_bus_error_free(&error);
|
||||||
sd_bus_message_unref(msg);
|
sd_bus_message_unref(msg);
|
||||||
@ -68,7 +70,7 @@ static ExitCode fromString(const char *str)
|
|||||||
std::exit(static_cast<int>(ret));
|
std::exit(static_cast<int>(ret));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int processExecStart(msg_ptr &msg, const std::deque<std::string_view> &execArgs)
|
int processExecStart(msg_ptr &msg, const std::deque<std::string_view> &execArgs)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
if (ret = sd_bus_message_append(msg, "s", "ExecStart"); ret < 0) {
|
if (ret = sd_bus_message_append(msg, "s", "ExecStart"); ret < 0) {
|
||||||
@ -139,7 +141,7 @@ static int processExecStart(msg_ptr &msg, const std::deque<std::string_view> &ex
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int processKVPair(msg_ptr &msg, const std::map<std::string_view, std::string_view> &props)
|
int processKVPair(msg_ptr &msg, const std::map<std::string_view, std::string_view> &props)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
if (!props.empty()) {
|
if (!props.empty()) {
|
||||||
@ -155,7 +157,7 @@ static int processKVPair(msg_ptr &msg, const std::map<std::string_view, std::str
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string cmdParse(msg_ptr &msg, std::deque<std::string_view> &&cmdLines)
|
std::string cmdParse(msg_ptr &msg, std::deque<std::string_view> &&cmdLines)
|
||||||
{
|
{
|
||||||
std::string serviceName{"internalError"};
|
std::string serviceName{"internalError"};
|
||||||
std::map<std::string_view, std::string_view> props;
|
std::map<std::string_view, std::string_view> props;
|
||||||
@ -241,6 +243,11 @@ static std::string cmdParse(msg_ptr &msg, std::deque<std::string_view> &&cmdLine
|
|||||||
return serviceName;
|
return serviceName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ret = sd_bus_message_append(msg, "(sv)", "Slice", "s", "app.slice"); ret < 0) {
|
||||||
|
sd_journal_perror("append application slice failed.");
|
||||||
|
return serviceName;
|
||||||
|
}
|
||||||
|
|
||||||
if (ret = sd_bus_message_open_container(msg, SD_BUS_TYPE_STRUCT, "sv"); ret < 0) {
|
if (ret = sd_bus_message_open_container(msg, SD_BUS_TYPE_STRUCT, "sv"); ret < 0) {
|
||||||
sd_journal_perror("open struct failed.");
|
sd_journal_perror("open struct failed.");
|
||||||
return serviceName;
|
return serviceName;
|
||||||
@ -300,7 +307,7 @@ int jobRemovedReceiver(sd_bus_message *m, void *userdata, sd_bus_error *ret_erro
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_dbus_message(sd_bus *bus)
|
int process_dbus_message(sd_bus *bus)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
ret = sd_bus_process(bus, nullptr);
|
ret = sd_bus_process(bus, nullptr);
|
||||||
@ -322,6 +329,8 @@ static int process_dbus_message(sd_bus *bus)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
int main(int argc, const char *argv[])
|
int main(int argc, const char *argv[])
|
||||||
{
|
{
|
||||||
sd_bus_error error{SD_BUS_ERROR_NULL};
|
sd_bus_error error{SD_BUS_ERROR_NULL};
|
||||||
|
@ -9,12 +9,14 @@
|
|||||||
#include "dbus/applicationmanager1service.h"
|
#include "dbus/applicationmanager1service.h"
|
||||||
#include "cgroupsidentifier.h"
|
#include "cgroupsidentifier.h"
|
||||||
|
|
||||||
static void registerComplexDbusType()
|
namespace {
|
||||||
|
void registerComplexDbusType()
|
||||||
{
|
{
|
||||||
qDBusRegisterMetaType<QMap<QString, QDBusUnixFileDescriptor>>();
|
qDBusRegisterMetaType<QMap<QString, QDBusUnixFileDescriptor>>();
|
||||||
qDBusRegisterMetaType<QMap<uint, QMap<QString, QDBusUnixFileDescriptor>>>();
|
qDBusRegisterMetaType<QMap<uint, QMap<QString, QDBusUnixFileDescriptor>>>();
|
||||||
qDBusRegisterMetaType<IconMap>();
|
qDBusRegisterMetaType<IconMap>();
|
||||||
}
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@ -22,7 +24,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
auto &bus = ApplicationManager1DBus::instance();
|
auto &bus = ApplicationManager1DBus::instance();
|
||||||
bus.initGlobalServerBus(DBusType::Session);
|
bus.initGlobalServerBus(DBusType::Session);
|
||||||
bus.setDestBus("");
|
bus.setDestBus();
|
||||||
auto &AMBus = bus.globalServerBus();
|
auto &AMBus = bus.globalServerBus();
|
||||||
|
|
||||||
registerComplexDbusType();
|
registerComplexDbusType();
|
||||||
|
5
debian/control
vendored
5
debian/control
vendored
@ -3,6 +3,11 @@ Section: devel
|
|||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: Chen Linxuan <chenlinxuan@uniontech.com>
|
Maintainer: Chen Linxuan <chenlinxuan@uniontech.com>
|
||||||
Build-Depends:
|
Build-Depends:
|
||||||
|
cmake,
|
||||||
|
libsystemd-dev,
|
||||||
|
qt6-base-dev,
|
||||||
|
libgtest-dev,
|
||||||
|
pkg-config
|
||||||
Standards-Version: 4.1.3
|
Standards-Version: 4.1.3
|
||||||
Homepage: https://github.com/linuxdeepin/dde-application-manager
|
Homepage: https://github.com/linuxdeepin/dde-application-manager
|
||||||
Package: dde-application-manager-reborn
|
Package: dde-application-manager-reborn
|
||||||
|
@ -16,14 +16,13 @@ IdentifyRet CGroupsIdentifier::Identify(pid_t pid)
|
|||||||
qWarning() << "open " << AppCgroupPath << "failed: " << AppCgroupFile.errorString();
|
qWarning() << "open " << AppCgroupPath << "failed: " << AppCgroupFile.errorString();
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto appInstance = parseCGroupsPath(
|
auto UnitStr = parseCGroupsPath(QString::fromLocal8Bit(AppCgroupFile.readAll())
|
||||||
AppCgroupFile.readAll().split(':').last().trimmed()); // FIXME: support CGroup version detection and multi-line parsing
|
.split(':', Qt::SkipEmptyParts)
|
||||||
auto appInstanceComponent = appInstance.split('@');
|
.last()
|
||||||
if (appInstanceComponent.count() != 2) {
|
.trimmed()); // FIXME: support CGroup version detection and multi-line parsing
|
||||||
qWarning() << "Application Instance format is invalid." << appInstanceComponent;
|
|
||||||
return {};
|
auto [appId, InstanceId] = processUnitName(UnitStr);
|
||||||
}
|
return {std::move(appId), std::move(InstanceId)};
|
||||||
return {appInstanceComponent.first(), appInstanceComponent.last()};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CGroupsIdentifier::parseCGroupsPath(const QString &CGP) noexcept
|
QString CGroupsIdentifier::parseCGroupsPath(const QString &CGP) noexcept
|
||||||
@ -32,8 +31,7 @@ QString CGroupsIdentifier::parseCGroupsPath(const QString &CGP) noexcept
|
|||||||
qWarning() << "CGroupPath is empty.";
|
qWarning() << "CGroupPath is empty.";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto unescapedCGP = unescapeString(CGP);
|
auto CGPSlices = CGP.split('/', Qt::SkipEmptyParts);
|
||||||
auto CGPSlices = unescapedCGP.split('/');
|
|
||||||
|
|
||||||
if (CGPSlices.first() != "user.slice") {
|
if (CGPSlices.first() != "user.slice") {
|
||||||
qWarning() << "unrecognized process.";
|
qWarning() << "unrecognized process.";
|
||||||
@ -51,7 +49,7 @@ QString CGroupsIdentifier::parseCGroupsPath(const QString &CGP) noexcept
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto appInstance = CGPSlices.last().split('.').first();
|
auto appInstance = CGPSlices.last();
|
||||||
if (appInstance.isEmpty()) {
|
if (appInstance.isEmpty()) {
|
||||||
qWarning() << "get AppId failed.";
|
qWarning() << "get AppId failed.";
|
||||||
return {};
|
return {};
|
||||||
|
@ -90,41 +90,6 @@ ApplicationManager1Service::ApplicationManager1Service(std::unique_ptr<Identifie
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QPair<QString, QString> ApplicationManager1Service::processUnitName(const QString &unitName) noexcept
|
|
||||||
{
|
|
||||||
QString instanceId;
|
|
||||||
QString applicationId;
|
|
||||||
|
|
||||||
if (unitName.endsWith(".service")) {
|
|
||||||
auto lastDotIndex = unitName.lastIndexOf('.');
|
|
||||||
auto app = unitName.sliced(0, lastDotIndex - 1); // remove suffix
|
|
||||||
|
|
||||||
if (app.contains('@')) {
|
|
||||||
auto atIndex = app.indexOf('@');
|
|
||||||
instanceId = app.sliced(atIndex + 1);
|
|
||||||
app.remove(atIndex, instanceId.length() + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
applicationId = app.split('-').last(); // drop launcher if it exists.
|
|
||||||
} else if (unitName.endsWith(".scope")) {
|
|
||||||
auto lastDotIndex = unitName.lastIndexOf('.');
|
|
||||||
auto app = unitName.sliced(0, lastDotIndex - 1);
|
|
||||||
|
|
||||||
auto components = app.split('-');
|
|
||||||
instanceId = components.takeLast();
|
|
||||||
applicationId = components.takeLast();
|
|
||||||
} else {
|
|
||||||
qDebug() << "it's not service or scope:" << unitName << "ignore.";
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (instanceId.isEmpty()) {
|
|
||||||
instanceId = QUuid::createUuid().toString(QUuid::Id128);
|
|
||||||
}
|
|
||||||
|
|
||||||
return qMakePair(unescapeApplicationId(applicationId), std::move(instanceId));
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QDBusObjectPath> ApplicationManager1Service::list() const
|
QList<QDBusObjectPath> ApplicationManager1Service::list() const
|
||||||
{
|
{
|
||||||
return m_applicationList.keys();
|
return m_applicationList.keys();
|
||||||
|
@ -62,8 +62,6 @@ private:
|
|||||||
std::unique_ptr<Identifier> m_identifier;
|
std::unique_ptr<Identifier> m_identifier;
|
||||||
QScopedPointer<JobManager1Service> m_jobManager{nullptr};
|
QScopedPointer<JobManager1Service> m_jobManager{nullptr};
|
||||||
QMap<QDBusObjectPath, QSharedPointer<ApplicationService>> m_applicationList;
|
QMap<QDBusObjectPath, QSharedPointer<ApplicationService>> m_applicationList;
|
||||||
|
|
||||||
static QPair<QString, QString> processUnitName(const QString &serviceName) noexcept;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -64,7 +64,7 @@ public Q_SLOTS:
|
|||||||
private:
|
private:
|
||||||
friend class ApplicationManager1Service;
|
friend class ApplicationManager1Service;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
ApplicationService(T &&source, ApplicationManager1Service *parent)
|
explicit ApplicationService(T &&source, ApplicationManager1Service *parent = nullptr)
|
||||||
: m_parent(parent)
|
: m_parent(parent)
|
||||||
, m_desktopSource(std::forward<T>(source))
|
, m_desktopSource(std::forward<T>(source))
|
||||||
{
|
{
|
||||||
@ -84,7 +84,9 @@ private:
|
|||||||
m_isPersistence = true;
|
m_isPersistence = true;
|
||||||
sourceFile.setFileName(m_desktopSource.m_file.filePath());
|
sourceFile.setFileName(m_desktopSource.m_file.filePath());
|
||||||
if (!sourceFile.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text)) {
|
if (!sourceFile.open(QFile::ExistingOnly | QFile::ReadOnly | QFile::Text)) {
|
||||||
|
#ifndef DEBUG_MODE
|
||||||
qCritical() << "desktop file can't open:" << m_desktopSource.m_file.filePath() << sourceFile.errorString();
|
qCritical() << "desktop file can't open:" << m_desktopSource.m_file.filePath() << sourceFile.errorString();
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sourceStream.setDevice(&sourceFile);
|
sourceStream.setDevice(&sourceFile);
|
||||||
|
58
src/global.h
58
src/global.h
@ -18,6 +18,7 @@
|
|||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QDBusObjectPath>
|
#include <QDBusObjectPath>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <QUuid>
|
||||||
#include "constant.h"
|
#include "constant.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
@ -143,7 +144,7 @@ public:
|
|||||||
return m_destConnection.value();
|
return m_destConnection.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDestBus(const QString &destAddress)
|
void setDestBus(const QString &destAddress = "")
|
||||||
{
|
{
|
||||||
if (m_destConnection) {
|
if (m_destConnection) {
|
||||||
m_destConnection->disconnectFromBus(ApplicationManagerDestDBusName);
|
m_destConnection->disconnectFromBus(ApplicationManagerDestDBusName);
|
||||||
@ -206,26 +207,6 @@ inline QLocale getUserLocale()
|
|||||||
return QLocale::system(); // current use env
|
return QLocale::system(); // current use env
|
||||||
}
|
}
|
||||||
|
|
||||||
inline QString unescapeString(const QString &input)
|
|
||||||
{
|
|
||||||
QRegularExpression regex("\\\\x([0-9A-Fa-f]{2})");
|
|
||||||
QRegularExpressionMatchIterator it = regex.globalMatch(input);
|
|
||||||
QString output{input};
|
|
||||||
|
|
||||||
while (it.hasNext()) {
|
|
||||||
QRegularExpressionMatch match = it.next();
|
|
||||||
bool ok;
|
|
||||||
// Get the hexadecimal value from the match and convert it to a number.
|
|
||||||
int asciiValue = match.captured(1).toInt(&ok, 16);
|
|
||||||
if (ok) {
|
|
||||||
// Convert the ASCII value to a QChar and perform the replacement.
|
|
||||||
output.replace(match.capturedStart(), match.capturedLength(), QChar(asciiValue));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline QString escapeToObjectPath(const QString &str)
|
inline QString escapeToObjectPath(const QString &str)
|
||||||
{
|
{
|
||||||
if (str.isEmpty()) {
|
if (str.isEmpty()) {
|
||||||
@ -333,4 +314,39 @@ inline QStringList getXDGDataDirs()
|
|||||||
return XDGDataDirs;
|
return XDGDataDirs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline QPair<QString, QString> processUnitName(const QString &unitName)
|
||||||
|
{
|
||||||
|
QString instanceId;
|
||||||
|
QString applicationId;
|
||||||
|
|
||||||
|
if (unitName.endsWith(".service")) {
|
||||||
|
auto lastDotIndex = unitName.lastIndexOf('.');
|
||||||
|
auto app = unitName.sliced(0, lastDotIndex); // remove suffix
|
||||||
|
|
||||||
|
if (app.contains('@')) {
|
||||||
|
auto atIndex = app.indexOf('@');
|
||||||
|
instanceId = app.sliced(atIndex + 1);
|
||||||
|
app.remove(atIndex, instanceId.length() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
applicationId = app.split('-').last(); // drop launcher if it exists.
|
||||||
|
} else if (unitName.endsWith(".scope")) {
|
||||||
|
auto lastDotIndex = unitName.lastIndexOf('.');
|
||||||
|
auto app = unitName.sliced(0, lastDotIndex);
|
||||||
|
|
||||||
|
auto components = app.split('-');
|
||||||
|
instanceId = components.takeLast();
|
||||||
|
applicationId = components.takeLast();
|
||||||
|
} else {
|
||||||
|
qDebug() << "it's not service or scope:" << unitName << "ignore.";
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instanceId.isEmpty()) {
|
||||||
|
instanceId = QUuid::createUuid().toString(QUuid::Id128);
|
||||||
|
}
|
||||||
|
|
||||||
|
return qMakePair(unescapeApplicationId(applicationId), std::move(instanceId));
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -18,7 +18,16 @@ target_link_libraries(${BIN_NAME} PRIVATE
|
|||||||
dde_am_static
|
dde_am_static
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_options(${BIN_NAME} PRIVATE "-fno-access-control")
|
target_compile_options(${BIN_NAME} PRIVATE
|
||||||
|
-fno-access-control
|
||||||
|
-fsanitize=undefined
|
||||||
|
-fsanitize=address
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_options(${BIN_NAME} PRIVATE
|
||||||
|
-fsanitize=undefined
|
||||||
|
-fsanitize=address
|
||||||
|
)
|
||||||
|
|
||||||
add_test(
|
add_test(
|
||||||
NAME UnitTest
|
NAME UnitTest
|
||||||
|
154
tests/ut_applicationmanager.cpp
Normal file
154
tests/ut_applicationmanager.cpp
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "dbus/applicationmanager1service.h"
|
||||||
|
#include "dbus/applicationservice.h"
|
||||||
|
#include "cgroupsidentifier.h"
|
||||||
|
#include "constant.h"
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <QDBusConnection>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <thread>
|
||||||
|
#include <chrono>
|
||||||
|
#include <QDBusUnixFileDescriptor>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int pidfd_open(pid_t pid, uint flags)
|
||||||
|
{
|
||||||
|
return syscall(SYS_pidfd_open, pid, flags);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
class TestApplicationManager : public testing::Test
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void SetUpTestCase()
|
||||||
|
{
|
||||||
|
auto &bus = ApplicationManager1DBus::instance();
|
||||||
|
bus.initGlobalServerBus(DBusType::Session);
|
||||||
|
bus.setDestBus();
|
||||||
|
|
||||||
|
m_am = new ApplicationManager1Service{std::make_unique<CGroupsIdentifier>(), bus.globalServerBus()};
|
||||||
|
|
||||||
|
DesktopFile file{"/usr/share/applications/test-Application.desktop", "test-Application", 0};
|
||||||
|
QSharedPointer<ApplicationService> app = QSharedPointer<ApplicationService>::create(std::move(file));
|
||||||
|
QSharedPointer<InstanceService> instance =
|
||||||
|
QSharedPointer<InstanceService>::create(InstancePath.path().split('/').last(), ApplicationPath.path(), QString{"/"});
|
||||||
|
app->m_Instances.insert(InstancePath, instance);
|
||||||
|
m_am->m_applicationList.insert(ApplicationPath, app);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void TearDownTestCase() { m_am->deleteLater(); }
|
||||||
|
|
||||||
|
static inline ApplicationManager1Service *m_am{nullptr};
|
||||||
|
const static inline QDBusObjectPath ApplicationPath{DDEApplicationManager1ApplicationObjectPath +
|
||||||
|
QUuid::createUuid().toString(QUuid::Id128)};
|
||||||
|
const static inline QDBusObjectPath InstancePath{DDEApplicationManager1InstanceObjectPath +
|
||||||
|
QUuid::createUuid().toString(QUuid::Id128)};
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(TestApplicationManager, list)
|
||||||
|
{
|
||||||
|
auto lists = m_am->list();
|
||||||
|
EXPECT_EQ(lists.first(), ApplicationPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TestApplicationManager, application)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(m_am->Application("test-Application"), ApplicationPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TestApplicationManager, identifyService)
|
||||||
|
{
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
// for service unit
|
||||||
|
auto workingDir = QDir::cleanPath(QDir::current().absolutePath() + QDir::separator() + ".." + QDir::separator() + "tools");
|
||||||
|
QFile pidFile{workingDir + QDir::separator() + "pid.txt"};
|
||||||
|
if (pidFile.exists()) {
|
||||||
|
ASSERT_TRUE(pidFile.remove());
|
||||||
|
}
|
||||||
|
|
||||||
|
QProcess fakeServiceProc;
|
||||||
|
fakeServiceProc.setWorkingDirectory(workingDir);
|
||||||
|
auto InstanceId = InstancePath.path().split('/').last();
|
||||||
|
fakeServiceProc.start("/usr/bin/systemd-run",
|
||||||
|
{{QString{R"(--unit=app-DDE-test\x2dApplication@%1.service)"}.arg(InstanceId)},
|
||||||
|
{"--user"},
|
||||||
|
{QString{"--working-directory=%1"}.arg(workingDir)},
|
||||||
|
{"--slice=app.slice"},
|
||||||
|
{"./fake-process.sh"}});
|
||||||
|
fakeServiceProc.waitForFinished();
|
||||||
|
if (fakeServiceProc.exitStatus() != QProcess::ExitStatus::NormalExit) {
|
||||||
|
GTEST_SKIP() << "invoke systemd-run failed.";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(100ms);
|
||||||
|
|
||||||
|
auto success = pidFile.open(QFile::ReadOnly | QFile::Text | QFile::ExistingOnly);
|
||||||
|
EXPECT_TRUE(success);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
qWarning() << pidFile.errorString();
|
||||||
|
fakeServiceProc.terminate();
|
||||||
|
ASSERT_TRUE(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok{false};
|
||||||
|
auto fakePid = pidFile.readLine().toInt(&ok);
|
||||||
|
ASSERT_TRUE(ok);
|
||||||
|
|
||||||
|
auto pidfd = pidfd_open(fakePid, 0);
|
||||||
|
ASSERT_TRUE(pidfd > 0) << std::strerror(errno);
|
||||||
|
QDBusObjectPath application;
|
||||||
|
QDBusObjectPath application_instance;
|
||||||
|
auto appId = m_am->Identify(QDBusUnixFileDescriptor{pidfd}, application, application_instance);
|
||||||
|
EXPECT_EQ(appId.toStdString(), QString{"test-Application"}.toStdString());
|
||||||
|
EXPECT_EQ(application.path().toStdString(), ApplicationPath.path().toStdString());
|
||||||
|
EXPECT_EQ(application_instance.path().toStdString(), InstancePath.path().toStdString());
|
||||||
|
close(pidfd);
|
||||||
|
|
||||||
|
if (pidFile.exists()) {
|
||||||
|
pidFile.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// for scope unit
|
||||||
|
ASSERT_TRUE(QProcess::startDetached("/usr/bin/systemd-run",
|
||||||
|
{{"--scope"},
|
||||||
|
{QString{R"(--unit=app-DDE-test\x2dApplication-%1.scope)"}.arg(InstanceId)},
|
||||||
|
{"--user"},
|
||||||
|
{QString{"--working-directory=%1"}.arg(workingDir)},
|
||||||
|
{"--slice=app.slice"},
|
||||||
|
{"./fake-process.sh"},
|
||||||
|
{"Scope"}},
|
||||||
|
workingDir));
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(100ms);
|
||||||
|
|
||||||
|
success = pidFile.open(QFile::ReadOnly | QFile::Text | QFile::ExistingOnly);
|
||||||
|
EXPECT_TRUE(success);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
qWarning() << pidFile.errorString();
|
||||||
|
ASSERT_TRUE(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = false;
|
||||||
|
fakePid = pidFile.readLine().toInt(&ok);
|
||||||
|
ASSERT_TRUE(ok);
|
||||||
|
|
||||||
|
pidfd = pidfd_open(fakePid, 0);
|
||||||
|
ASSERT_TRUE(pidfd > 0) << std::strerror(errno);
|
||||||
|
|
||||||
|
appId = m_am->Identify(QDBusUnixFileDescriptor{pidfd}, application, application_instance);
|
||||||
|
EXPECT_EQ(appId.toStdString(), QString{"test-Application"}.toStdString());
|
||||||
|
EXPECT_EQ(application.path().toStdString(), ApplicationPath.path().toStdString());
|
||||||
|
EXPECT_EQ(application_instance.path().toStdString(), InstancePath.path().toStdString());
|
||||||
|
close(pidfd);
|
||||||
|
|
||||||
|
if (pidFile.exists()) {
|
||||||
|
pidFile.remove();
|
||||||
|
}
|
||||||
|
}
|
@ -30,8 +30,6 @@ public:
|
|||||||
|
|
||||||
static void TearDownTestCase() { qputenv("XDG_DATA_DIRS", env); }
|
static void TearDownTestCase() { qputenv("XDG_DATA_DIRS", env); }
|
||||||
|
|
||||||
void SetUp() override {}
|
|
||||||
void TearDown() override {}
|
|
||||||
QSharedPointer<DesktopFile> file() { return m_file; }
|
QSharedPointer<DesktopFile> file() { return m_file; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -43,5 +43,5 @@ TEST_F(TestJobManager, addJob)
|
|||||||
return QVariant::fromValue(true);
|
return QVariant::fromValue(true);
|
||||||
},
|
},
|
||||||
args);
|
args);
|
||||||
QThread::sleep(1); // force wait
|
QThreadPool::globalInstance()->waitForDone();
|
||||||
}
|
}
|
||||||
|
9
tools/fake-process.sh
Executable file
9
tools/fake-process.sh
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
|
||||||
|
echo $$ > pid.txt
|
||||||
|
sleep 1s
|
||||||
|
exit 0
|
@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
|
# SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user