refact: change dbus api and service impl
1. change IconName and DisplayName to method 2. refactor impl of GetManagedObject and move it to global.h 3. refactor impl of JobService::status 4. add ut_job.cpp Signed-off-by: ComixHe <heyuming@deepin.org>
This commit is contained in:
parent
d49a99d252
commit
0e7d84f61d
@ -17,10 +17,6 @@
|
||||
|
||||
<property name="AutoStart" type="b" access="readwrite"/>
|
||||
|
||||
<property name="IconName" type="s" access="read"/>
|
||||
|
||||
<property name="DisplayName" type="s" access="read"/>
|
||||
|
||||
<property name="Instances" type="ao" access="read">
|
||||
<annotation
|
||||
name="org.freedesktop.DBus.Description"
|
||||
@ -102,5 +98,23 @@
|
||||
this method will use the locale config of that user."
|
||||
/>
|
||||
</method>
|
||||
|
||||
<method name="GetIconName">
|
||||
<arg name="action" type="s" direction="in"/>
|
||||
<arg name="name" type="s" direction="out"/>
|
||||
<annotation
|
||||
name="org.freedesktop.DBus.Description"
|
||||
value="The meaning of arg `env` is same as which in GetActionName."
|
||||
/>
|
||||
</method>
|
||||
|
||||
<method name="GetDisplayName">
|
||||
<arg name="env" type="as" direction="in"/>
|
||||
<arg name="name" type="s" direction="out"/>
|
||||
<annotation
|
||||
name="org.freedesktop.DBus.Description"
|
||||
value="The meaning of arg `env` is same as which in GetActionName."
|
||||
/>
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
||||
|
@ -218,12 +218,5 @@ void ApplicationManager1Service::UpdateApplicationInfo(const QStringList &appIdL
|
||||
|
||||
ObjectMap ApplicationManager1Service::GetManagedObjects() const
|
||||
{
|
||||
ObjectMap objs;
|
||||
|
||||
for (const auto &[key, value] : m_applicationList.asKeyValueRange()) {
|
||||
auto interfaces = getInterfacesListFromObject(value.data());
|
||||
objs.insert(key, interfaces);
|
||||
}
|
||||
|
||||
return objs;
|
||||
return dumpDBusObject(m_applicationList);
|
||||
}
|
||||
|
@ -83,7 +83,8 @@ private:
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
QSharedPointer<ApplicationService> makeApplication(T &&source, ApplicationManager1Service *parent)
|
||||
QSharedPointer<ApplicationService> makeApplication(T &&source,
|
||||
ApplicationManager1Service *parent) // NOTE: maybe we should refactor
|
||||
{
|
||||
static_assert(std::is_same_v<T, DesktopFile> or std::is_same_v<T, QString>, "param type must be QString or DesktopFile.");
|
||||
QString objectPath;
|
||||
|
@ -25,7 +25,7 @@ ApplicationService::~ApplicationService()
|
||||
}
|
||||
}
|
||||
|
||||
QString ApplicationService::GetActionName(const QString &identifier, const QStringList &env)
|
||||
QString ApplicationService::GetActionName(const QString &identifier, const QStringList &env) const
|
||||
{
|
||||
const auto &supportedActions = actions();
|
||||
if (supportedActions.isEmpty()) {
|
||||
@ -68,6 +68,67 @@ QString ApplicationService::GetActionName(const QString &identifier, const QStri
|
||||
return name;
|
||||
}
|
||||
|
||||
QString ApplicationService::GetDisplayName(const QStringList &env) const
|
||||
{
|
||||
const auto &displayName = m_entry->value(DesktopFileEntryKey, "Name");
|
||||
if (!displayName) {
|
||||
return {};
|
||||
}
|
||||
|
||||
QString locale{""};
|
||||
bool ok;
|
||||
if (!env.isEmpty()) {
|
||||
QString lcStr;
|
||||
for (const auto &lc : env) {
|
||||
if (lc.startsWith("LANG")) {
|
||||
locale = lc.split('=').last();
|
||||
}
|
||||
|
||||
if (lc.startsWith("LC_ALL")) {
|
||||
locale = lc.split('=').last();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QLocale lc = locale.isEmpty() ? getUserLocale() : QLocale{locale};
|
||||
|
||||
const auto &name = displayName->toLocaleString(lc, ok);
|
||||
if (!ok) {
|
||||
qWarning() << "convert to locale string failed, dest locale:" << lc;
|
||||
return {};
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
QString ApplicationService::GetIconName(const QString &action) const
|
||||
{
|
||||
std::optional<DesktopEntry::Value> iconName{std::nullopt};
|
||||
|
||||
if (action.isEmpty()) {
|
||||
iconName = m_entry->value(DesktopFileEntryKey, "Icon");
|
||||
|
||||
} else {
|
||||
const auto &supportedActions = actions();
|
||||
|
||||
if (auto index = supportedActions.indexOf(action); index == -1) {
|
||||
qWarning() << "can't find " << action << " in supported actions List.";
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto &actionHeader = QString{"%1%2"}.arg(DesktopFileActionKey, action);
|
||||
iconName = m_entry->value(actionHeader, "Icon");
|
||||
}
|
||||
|
||||
if (!iconName) {
|
||||
return {};
|
||||
}
|
||||
|
||||
bool ok{false};
|
||||
const auto &name = iconName->toIconString(ok);
|
||||
return ok ? name : "";
|
||||
}
|
||||
|
||||
QDBusObjectPath ApplicationService::Launch(QString action, QStringList fields, QVariantMap options)
|
||||
{
|
||||
QString execStr;
|
||||
@ -208,14 +269,7 @@ QStringList ApplicationService::actions() const noexcept
|
||||
|
||||
ObjectMap ApplicationService::GetManagedObjects() const
|
||||
{
|
||||
ObjectMap objs;
|
||||
|
||||
for (const auto &[key, value] : m_Instances.asKeyValueRange()) {
|
||||
auto interfaces = getInterfacesListFromObject(value.data());
|
||||
objs.insert(key, interfaces);
|
||||
}
|
||||
|
||||
return objs;
|
||||
return dumpDBusObject(m_Instances);
|
||||
}
|
||||
|
||||
QString ApplicationService::id() const noexcept
|
||||
@ -254,50 +308,6 @@ QList<QDBusObjectPath> ApplicationService::instances() const noexcept
|
||||
return m_Instances.keys();
|
||||
}
|
||||
|
||||
QString ApplicationService::iconName() const noexcept
|
||||
{
|
||||
if (m_entry.isNull()) {
|
||||
qWarning() << "desktop entry is empty, isPersistence:" << m_isPersistence;
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto &actions = m_entry->value(DesktopFileEntryKey, "Icon");
|
||||
if (!actions) {
|
||||
return {};
|
||||
}
|
||||
|
||||
bool ok{false};
|
||||
const auto &icon = actions->toIconString(ok);
|
||||
if (!ok) {
|
||||
qWarning() << "Icon convert to String failed.";
|
||||
return {};
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
QString ApplicationService::displayName() const noexcept
|
||||
{
|
||||
if (m_entry.isNull()) {
|
||||
qWarning() << "desktop entry is empty, isPersistence:" << m_isPersistence;
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto &actions = m_entry->value(DesktopFileEntryKey, "Name");
|
||||
if (!actions) {
|
||||
return {};
|
||||
}
|
||||
|
||||
bool ok{false};
|
||||
const auto &name = actions->toString(ok);
|
||||
if (!ok) {
|
||||
qWarning() << "Icon convert to String failed.";
|
||||
return {};
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
bool ApplicationService::addOneInstance(const QString &instanceId, const QString &application, const QString &systemdUnitPath)
|
||||
{
|
||||
auto service = new InstanceService{instanceId, application, systemdUnitPath};
|
||||
|
@ -48,12 +48,6 @@ public:
|
||||
Q_PROPERTY(QList<QDBusObjectPath> Instances READ instances)
|
||||
[[nodiscard]] QList<QDBusObjectPath> instances() const noexcept;
|
||||
|
||||
Q_PROPERTY(QString IconName READ iconName CONSTANT)
|
||||
[[nodiscard]] QString iconName() const noexcept;
|
||||
|
||||
Q_PROPERTY(QString DisplayName READ displayName CONSTANT)
|
||||
[[nodiscard]] QString displayName() const noexcept;
|
||||
|
||||
[[nodiscard]] QDBusObjectPath findInstance(const QString &instanceId) const;
|
||||
|
||||
[[nodiscard]] const QString &getLauncher() const noexcept { return m_launcher; }
|
||||
@ -65,8 +59,10 @@ public:
|
||||
void removeAllInstance();
|
||||
|
||||
public Q_SLOTS:
|
||||
QString GetActionName(const QString &identifier, const QStringList &env);
|
||||
[[nodiscard]] QString GetActionName(const QString &identifier, const QStringList &env) const;
|
||||
QDBusObjectPath Launch(QString action, QStringList fields, QVariantMap options);
|
||||
[[nodiscard]] QString GetIconName(const QString &action) const;
|
||||
[[nodiscard]] QString GetDisplayName(const QStringList &env) const;
|
||||
[[nodiscard]] ObjectMap GetManagedObjects() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
|
@ -11,27 +11,29 @@ JobService::JobService(const QFuture<QVariantList> &job)
|
||||
|
||||
JobService::~JobService() = default;
|
||||
|
||||
QString JobService::status() const // FIXME: job status aren't mutually exclusive
|
||||
QString JobService::status() const
|
||||
{
|
||||
if (m_job.isFinished()) {
|
||||
return "finished";
|
||||
}
|
||||
if (m_job.isCanceled()) {
|
||||
return "canceled";
|
||||
}
|
||||
if (m_job.isSuspended()) {
|
||||
return "suspended";
|
||||
}
|
||||
if (m_job.isSuspending()) {
|
||||
return "suspending";
|
||||
}
|
||||
if (m_job.isStarted()) {
|
||||
return "started";
|
||||
if (m_job.isRunning()) {
|
||||
if (m_job.isSuspending()) {
|
||||
return "suspending";
|
||||
}
|
||||
if (m_job.isSuspended()) {
|
||||
return "suspended";
|
||||
}
|
||||
return "running";
|
||||
}
|
||||
|
||||
if (m_job.isCanceled()) {
|
||||
return "canceled";
|
||||
}
|
||||
|
||||
if (m_job.isFinished()) {
|
||||
return "finished";
|
||||
}
|
||||
}
|
||||
if (m_job.isRunning()) {
|
||||
return "running";
|
||||
}
|
||||
Q_UNREACHABLE();
|
||||
|
||||
return "pending";
|
||||
}
|
||||
|
||||
void JobService::Cancel()
|
||||
|
13
src/global.h
13
src/global.h
@ -361,4 +361,17 @@ inline QPair<QString, QString> processUnitName(const QString &unitName)
|
||||
return qMakePair(unescapeApplicationId(applicationId), std::move(instanceId));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ObjectMap dumpDBusObject(const QMap<QDBusObjectPath, QSharedPointer<T>> &map)
|
||||
{
|
||||
ObjectMap objs;
|
||||
|
||||
for (const auto &[key, value] : map.asKeyValueRange()) {
|
||||
auto interfaces = getInterfacesListFromObject(value.data());
|
||||
objs.insert(key, interfaces);
|
||||
}
|
||||
|
||||
return objs;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
104
tests/ut_job.cpp
Normal file
104
tests/ut_job.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "dbus/jobservice.h"
|
||||
#include <gtest/gtest.h>
|
||||
#include <QFuture>
|
||||
#include <QPromise>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <QSemaphore>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
class TestJob : public testing::Test
|
||||
{
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
QPromise<QVariantList> promise;
|
||||
m_jobService = new JobService{promise.future()};
|
||||
|
||||
m_thread = QThread::create(
|
||||
[](QPromise<QVariantList> promise) {
|
||||
std::this_thread::sleep_for(2ms);
|
||||
promise.start();
|
||||
std::this_thread::sleep_for(1ms);
|
||||
if (promise.isCanceled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(1ms);
|
||||
promise.suspendIfRequested();
|
||||
std::this_thread::sleep_for(1ms);
|
||||
|
||||
std::size_t x{0};
|
||||
for (std::size_t i = 0; i < 20000; ++i) {
|
||||
x += 1;
|
||||
}
|
||||
|
||||
promise.addResult(QVariantList{QVariant::fromValue<std::size_t>(x)});
|
||||
promise.finish();
|
||||
},
|
||||
std::move(promise));
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
m_thread->quit();
|
||||
m_thread->deleteLater();
|
||||
m_thread = nullptr;
|
||||
|
||||
m_jobService->deleteLater();
|
||||
m_jobService = nullptr;
|
||||
}
|
||||
|
||||
QThread *m_thread{nullptr};
|
||||
JobService *m_jobService{nullptr};
|
||||
};
|
||||
|
||||
TEST_F(TestJob, cancelJob)
|
||||
{
|
||||
m_thread->start();
|
||||
|
||||
std::this_thread::sleep_for(1ms);
|
||||
EXPECT_EQ(m_jobService->status().toStdString(), std::string{"pending"});
|
||||
std::this_thread::sleep_for(2ms);
|
||||
EXPECT_EQ(m_jobService->status().toStdString(), std::string{"running"});
|
||||
|
||||
m_jobService->Cancel();
|
||||
|
||||
std::this_thread::sleep_for(1ms);
|
||||
|
||||
EXPECT_EQ(m_jobService->status().toStdString(), std::string{"canceled"});
|
||||
}
|
||||
|
||||
TEST_F(TestJob, suspendAndResumeJob)
|
||||
{
|
||||
m_thread->start();
|
||||
|
||||
std::this_thread::sleep_for(3ms);
|
||||
|
||||
EXPECT_EQ(m_jobService->status().toStdString(), std::string{"running"});
|
||||
|
||||
m_jobService->Suspend();
|
||||
|
||||
std::this_thread::sleep_for(1ms);
|
||||
|
||||
EXPECT_EQ(m_jobService->status().toStdString(), std::string{"suspending"});
|
||||
std::this_thread::sleep_for(1ms);
|
||||
EXPECT_EQ(m_jobService->status().toStdString(), std::string{"suspended"});
|
||||
m_jobService->Resume();
|
||||
|
||||
std::this_thread::sleep_for(1ms);
|
||||
EXPECT_EQ(m_jobService->status().toStdString(), std::string{"running"});
|
||||
|
||||
EXPECT_TRUE(m_thread->wait());
|
||||
EXPECT_EQ(m_jobService->status().toStdString(), std::string{"finished"});
|
||||
|
||||
auto ret = m_jobService->m_job.result();
|
||||
EXPECT_FALSE(ret.isEmpty());
|
||||
|
||||
EXPECT_EQ(ret.first().value<std::size_t>(), std::size_t{20000});
|
||||
}
|
@ -10,7 +10,7 @@ class TestJobManager : public testing::Test
|
||||
public:
|
||||
static void SetUpTestCase() { m_jobManager = new JobManager1Service(nullptr); }
|
||||
|
||||
static void TearDownTestCase() { delete m_jobManager; }
|
||||
static void TearDownTestCase() { m_jobManager->deleteLater(); }
|
||||
JobManager1Service &service() { return *m_jobManager; }
|
||||
|
||||
private:
|
||||
|
Loading…
Reference in New Issue
Block a user