refact: refactor method Identify and improve unit test

Signed-off-by: ComixHe <heyuming@deepin.org>
This commit is contained in:
ComixHe 2023-09-14 13:38:44 +08:00 committed by Comix
parent bc7fbfb3a1
commit ebb5f613c4
8 changed files with 90 additions and 39 deletions

View File

@ -15,8 +15,8 @@
<arg type="h" name="pidfd" direction="in" /> <arg type="h" name="pidfd" direction="in" />
<arg type="s" name="id" direction="out" /> <arg type="s" name="id" direction="out" />
<arg type="o" name="application" direction="out" /> <arg type="a{oa{sv}}" name="application_instance_info" direction="out" />
<arg type="o" name="application_instance" direction="out" /> <annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="ObjectMap"/>
<annotation <annotation
name="org.freedesktop.DBus.Description" name="org.freedesktop.DBus.Description"

View File

@ -17,8 +17,6 @@ Q_LOGGING_CATEGORY(DDEAMProf, "dde.am.prof", QtInfoMsg)
namespace { namespace {
void registerComplexDbusType() void registerComplexDbusType()
{ {
qDBusRegisterMetaType<QMap<QString, QDBusUnixFileDescriptor>>();
qDBusRegisterMetaType<QMap<uint, QMap<QString, QDBusUnixFileDescriptor>>>();
qRegisterMetaType<ObjectInterfaceMap>(); qRegisterMetaType<ObjectInterfaceMap>();
qDBusRegisterMetaType<ObjectInterfaceMap>(); qDBusRegisterMetaType<ObjectInterfaceMap>();
qRegisterMetaType<ObjectMap>(); qRegisterMetaType<ObjectMap>();
@ -46,7 +44,8 @@ int main(int argc, char *argv[])
auto storageDir = getXDGDataHome() + QDir::separator() + "deepin" + QDir::separator() + "ApplicationManager"; auto storageDir = getXDGDataHome() + QDir::separator() + "deepin" + QDir::separator() + "ApplicationManager";
auto storage = ApplicationManager1Storage::createApplicationManager1Storage(storageDir); auto storage = ApplicationManager1Storage::createApplicationManager1Storage(storageDir);
ApplicationManager1Service AMService{std::make_unique<CGroupsIdentifier>(), AMBus, storage}; ApplicationManager1Service AMService{std::make_unique<CGroupsIdentifier>(), storage};
AMService.initService(AMBus);
#ifdef PROFILING_MODE #ifdef PROFILING_MODE
auto end = std::chrono::high_resolution_clock::now(); auto end = std::chrono::high_resolution_clock::now();

View File

@ -19,19 +19,25 @@ IdentifyRet CGroupsIdentifier::Identify(pid_t pid)
auto UnitStr = parseCGroupsPath(AppCgroupFile); auto UnitStr = parseCGroupsPath(AppCgroupFile);
if (UnitStr.isEmpty()) {
qWarning() << "process CGroups file failed.";
return {};
}
auto [appId, launcher, InstanceId] = processUnitName(UnitStr); auto [appId, launcher, InstanceId] = processUnitName(UnitStr);
return {std::move(appId), std::move(InstanceId)}; return {std::move(appId), std::move(InstanceId)};
} }
QString CGroupsIdentifier::parseCGroupsPath(QFile &cgroupFile) noexcept QString CGroupsIdentifier::parseCGroupsPath(QFile &cgroupFile) noexcept
{ {
QTextStream stream{&cgroupFile}; QString content = cgroupFile.readAll();
if (content.isEmpty()) {
if (stream.atEnd()) {
qWarning() << "read from cgroup file failed:" << stream.status();
return {}; return {};
} }
QTextStream stream{&content};
stream.setEncoding(QStringConverter::Utf8); stream.setEncoding(QStringConverter::Utf8);
QString CGP; QString CGP;
while (!stream.atEnd()) { while (!stream.atEnd()) {
auto line = stream.readLine(); auto line = stream.readLine();

View File

@ -14,10 +14,13 @@
ApplicationManager1Service::~ApplicationManager1Service() = default; ApplicationManager1Service::~ApplicationManager1Service() = default;
ApplicationManager1Service::ApplicationManager1Service(std::unique_ptr<Identifier> ptr, ApplicationManager1Service::ApplicationManager1Service(std::unique_ptr<Identifier> ptr,
QDBusConnection &connection,
std::weak_ptr<ApplicationManager1Storage> storage) noexcept std::weak_ptr<ApplicationManager1Storage> storage) noexcept
: m_identifier(std::move(ptr)) : m_identifier(std::move(ptr))
, m_storage(std::move(storage)) , m_storage(std::move(storage))
{
}
void ApplicationManager1Service::initService(QDBusConnection &connection) noexcept
{ {
if (!connection.registerService(DDEApplicationManager1ServiceName)) { if (!connection.registerService(DDEApplicationManager1ServiceName)) {
qFatal("%s", connection.lastError().message().toLocal8Bit().data()); qFatal("%s", connection.lastError().message().toLocal8Bit().data());
@ -314,8 +317,7 @@ void ApplicationManager1Service::removeAllApplication() noexcept
} }
QString ApplicationManager1Service::Identify(const QDBusUnixFileDescriptor &pidfd, QString ApplicationManager1Service::Identify(const QDBusUnixFileDescriptor &pidfd,
QDBusObjectPath &application, ObjectMap &application_instance_info) const noexcept
QDBusObjectPath &application_instance)
{ {
if (!pidfd.isValid()) { if (!pidfd.isValid()) {
qWarning() << "pidfd isn't a valid unix file descriptor"; qWarning() << "pidfd isn't a valid unix file descriptor";
@ -353,15 +355,32 @@ QString ApplicationManager1Service::Identify(const QDBusUnixFileDescriptor &pidf
const auto ret = m_identifier->Identify(pid); const auto ret = m_identifier->Identify(pid);
if (ret.ApplicationId.isEmpty()) {
qInfo() << "Identify failed.";
return {};
}
auto app = std::find_if(m_applicationList.cbegin(), m_applicationList.cend(), [&ret](const auto &appPtr) { auto app = std::find_if(m_applicationList.cbegin(), m_applicationList.cend(), [&ret](const auto &appPtr) {
return appPtr->id() == ret.ApplicationId; return appPtr->id() == ret.ApplicationId;
}); });
if (app == m_applicationList.cend()) { if (app == m_applicationList.cend()) {
qWarning() << "can't find application:" << ret.ApplicationId; qWarning() << "can't find application:" << ret.ApplicationId;
return {}; return {};
} }
application = m_applicationList.key(*app);
application_instance = (*app)->findInstance(ret.InstanceId); auto instance = (*app)->findInstance(ret.InstanceId);
if (auto path = instance.path(); path.isEmpty()) {
qWarning() << "can't find instance:" << path;
return {};
}
auto instanceObj = (*app)->m_Instances.constFind(instance);
auto map = getChildInterfacesAndPropertiesFromObject(instanceObj->get());
application_instance_info.insert(instance, map);
return ret.ApplicationId; return ret.ApplicationId;
} }

View File

@ -24,7 +24,6 @@ class ApplicationManager1Service final : public QObject
Q_OBJECT Q_OBJECT
public: public:
explicit ApplicationManager1Service(std::unique_ptr<Identifier> ptr, explicit ApplicationManager1Service(std::unique_ptr<Identifier> ptr,
QDBusConnection &connection,
std::weak_ptr<ApplicationManager1Storage> storage) noexcept; std::weak_ptr<ApplicationManager1Storage> storage) noexcept;
~ApplicationManager1Service() override; ~ApplicationManager1Service() override;
ApplicationManager1Service(const ApplicationManager1Service &) = delete; ApplicationManager1Service(const ApplicationManager1Service &) = delete;
@ -35,6 +34,7 @@ public:
Q_PROPERTY(QList<QDBusObjectPath> List READ list NOTIFY listChanged) Q_PROPERTY(QList<QDBusObjectPath> List READ list NOTIFY listChanged)
[[nodiscard]] QList<QDBusObjectPath> list() const; [[nodiscard]] QList<QDBusObjectPath> list() const;
void initService(QDBusConnection &connection) noexcept;
bool addApplication(DesktopFile desktopFileSource) noexcept; bool addApplication(DesktopFile desktopFileSource) noexcept;
void removeOneApplication(const QDBusObjectPath &application) noexcept; void removeOneApplication(const QDBusObjectPath &application) noexcept;
void removeAllApplication() noexcept; void removeAllApplication() noexcept;
@ -44,7 +44,7 @@ public:
JobManager1Service &jobManager() noexcept { return *m_jobManager; } JobManager1Service &jobManager() noexcept { return *m_jobManager; }
public Q_SLOTS: public Q_SLOTS:
QString Identify(const QDBusUnixFileDescriptor &pidfd, QDBusObjectPath &application, QDBusObjectPath &application_instance); QString Identify(const QDBusUnixFileDescriptor &pidfd, ObjectMap &application_instance_info) const noexcept;
void ReloadApplications(); void ReloadApplications();
[[nodiscard]] ObjectMap GetManagedObjects() const; [[nodiscard]] ObjectMap GetManagedObjects() const;

View File

@ -4,12 +4,20 @@
#include <QCoreApplication> #include <QCoreApplication>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "global.h"
#include <QTimer> #include <QTimer>
#include <QDBusMetaType> #include <QDBusMetaType>
namespace { namespace {
void registerComplexDbusType() void registerComplexDbusType() // FIXME: test shouldn't associate with DBus
{ {
qRegisterMetaType<ObjectInterfaceMap>();
qDBusRegisterMetaType<ObjectInterfaceMap>();
qRegisterMetaType<ObjectMap>();
qDBusRegisterMetaType<ObjectMap>();
qDBusRegisterMetaType<QMap<QString, QString>>();
qRegisterMetaType<PropMap>();
qDBusRegisterMetaType<PropMap>();
qDBusRegisterMetaType<QDBusObjectPath>(); qDBusRegisterMetaType<QDBusObjectPath>();
} }
} // namespace } // namespace

View File

@ -6,6 +6,7 @@
#include "dbus/applicationservice.h" #include "dbus/applicationservice.h"
#include "cgroupsidentifier.h" #include "cgroupsidentifier.h"
#include "constant.h" #include "constant.h"
#include "dbus/instanceadaptor.h"
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <QDBusConnection> #include <QDBusConnection>
#include <QSharedPointer> #include <QSharedPointer>
@ -34,7 +35,7 @@ public:
bus.initGlobalServerBus(DBusType::Session); bus.initGlobalServerBus(DBusType::Session);
bus.setDestBus(); bus.setDestBus();
std::shared_ptr<ApplicationManager1Storage> tmp{nullptr}; std::shared_ptr<ApplicationManager1Storage> tmp{nullptr};
m_am = new ApplicationManager1Service{std::make_unique<CGroupsIdentifier>(), bus.globalServerBus(), tmp}; m_am = new ApplicationManager1Service{std::make_unique<CGroupsIdentifier>(), tmp};
auto ptr = std::make_unique<QFile>(QString{"/usr/share/applications/test-Application.desktop"}); auto ptr = std::make_unique<QFile>(QString{"/usr/share/applications/test-Application.desktop"});
DesktopFile file{std::move(ptr), "test-Application", 0, 0}; DesktopFile file{std::move(ptr), "test-Application", 0, 0};
QSharedPointer<ApplicationService> app = QSharedPointer<ApplicationService>::create(std::move(file), nullptr, tmp); QSharedPointer<ApplicationService> app = QSharedPointer<ApplicationService>::create(std::move(file), nullptr, tmp);
@ -42,13 +43,13 @@ public:
InstancePath.path().split('/').last(), ApplicationPath.path(), QString{"/"}, QString{"DDE"}); InstancePath.path().split('/').last(), ApplicationPath.path(), QString{"/"}, QString{"DDE"});
app->m_Instances.insert(InstancePath, instance); app->m_Instances.insert(InstancePath, instance);
m_am->m_applicationList.insert(ApplicationPath, app); m_am->m_applicationList.insert(ApplicationPath, app);
new InstanceAdaptor{instance.data()};
} }
static void TearDownTestCase() { m_am->deleteLater(); } static void TearDownTestCase() { m_am->deleteLater(); }
static inline ApplicationManager1Service *m_am{nullptr}; static inline ApplicationManager1Service *m_am{nullptr};
const static inline QDBusObjectPath ApplicationPath{QString{DDEApplicationManager1ObjectPath} + "/" + const static inline QDBusObjectPath ApplicationPath{QString{DDEApplicationManager1ObjectPath} + "/test_2dApplication"};
QUuid::createUuid().toString(QUuid::Id128)};
const static inline QDBusObjectPath InstancePath{ApplicationPath.path() + "/" + QUuid::createUuid().toString(QUuid::Id128)}; const static inline QDBusObjectPath InstancePath{ApplicationPath.path() + "/" + QUuid::createUuid().toString(QUuid::Id128)};
}; };
@ -96,12 +97,22 @@ TEST_F(TestApplicationManager, identifyService)
auto pidfd = pidfd_open(fakePid, 0); auto pidfd = pidfd_open(fakePid, 0);
ASSERT_TRUE(pidfd > 0) << std::strerror(errno); ASSERT_TRUE(pidfd > 0) << std::strerror(errno);
QDBusObjectPath application; ObjectMap instanceInfo;
QDBusObjectPath application_instance; auto appId = m_am->Identify(QDBusUnixFileDescriptor{pidfd}, instanceInfo);
auto appId = m_am->Identify(QDBusUnixFileDescriptor{pidfd}, application, application_instance);
EXPECT_EQ(appId.toStdString(), QString{"test-Application"}.toStdString()); 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()); auto instance = instanceInfo.constFind(InstancePath);
if (instance == instanceInfo.cend()) {
GTEST_SKIP_("couldn't find instance and skip.");
}
ObjectInterfaceMap map{{QString{InstanceInterface},
QVariantMap{{QString{"Application"}, ApplicationPath},
{QString{"SystemdUnitPath"}, QDBusObjectPath{"/"}},
{QString{"Launcher"}, QString{"DDE"}},
{QString{"Orphaned"}, false}}}};
EXPECT_EQ(instance.value(), map);
close(pidfd); close(pidfd);
if (pidFile.exists()) { if (pidFile.exists()) {
@ -136,10 +147,18 @@ TEST_F(TestApplicationManager, identifyService)
pidfd = pidfd_open(fakePid, 0); pidfd = pidfd_open(fakePid, 0);
ASSERT_TRUE(pidfd > 0) << std::strerror(errno); ASSERT_TRUE(pidfd > 0) << std::strerror(errno);
appId = m_am->Identify(QDBusUnixFileDescriptor{pidfd}, application, application_instance); instanceInfo.clear();
appId = m_am->Identify(QDBusUnixFileDescriptor{pidfd}, instanceInfo);
EXPECT_EQ(appId.toStdString(), QString{"test-Application"}.toStdString()); 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()); instance = instanceInfo.constFind(InstancePath);
if (instance == instanceInfo.cend()) {
GTEST_SKIP_("couldn't find instance and skip.");
}
EXPECT_EQ(instance.value(), map);
close(pidfd); close(pidfd);
if (pidFile.exists()) { if (pidFile.exists()) {

View File

@ -22,16 +22,16 @@ public:
m_thread = QThread::create( m_thread = QThread::create(
[](QPromise<QVariantList> promise) { [](QPromise<QVariantList> promise) {
std::this_thread::sleep_for(2ms); std::this_thread::sleep_for(4ms);
promise.start(); promise.start();
std::this_thread::sleep_for(1ms); std::this_thread::sleep_for(2ms);
if (promise.isCanceled()) { if (promise.isCanceled()) {
return; return;
} }
std::this_thread::sleep_for(1ms); std::this_thread::sleep_for(2ms);
promise.suspendIfRequested(); promise.suspendIfRequested();
std::this_thread::sleep_for(1ms); std::this_thread::sleep_for(2ms);
std::size_t x{0}; std::size_t x{0};
for (std::size_t i = 0; i < 20000; ++i) { for (std::size_t i = 0; i < 20000; ++i) {
@ -62,14 +62,14 @@ TEST_F(TestJob, cancelJob)
{ {
m_thread->start(); m_thread->start();
std::this_thread::sleep_for(1ms);
EXPECT_EQ(m_jobService->status().toStdString(), std::string{"pending"});
std::this_thread::sleep_for(2ms); std::this_thread::sleep_for(2ms);
EXPECT_EQ(m_jobService->status().toStdString(), std::string{"pending"});
std::this_thread::sleep_for(4ms);
EXPECT_EQ(m_jobService->status().toStdString(), std::string{"running"}); EXPECT_EQ(m_jobService->status().toStdString(), std::string{"running"});
m_jobService->Cancel(); m_jobService->Cancel();
std::this_thread::sleep_for(1ms); std::this_thread::sleep_for(2ms);
EXPECT_EQ(m_jobService->status().toStdString(), std::string{"canceled"}); EXPECT_EQ(m_jobService->status().toStdString(), std::string{"canceled"});
} }
@ -78,20 +78,20 @@ TEST_F(TestJob, suspendAndResumeJob)
{ {
m_thread->start(); m_thread->start();
std::this_thread::sleep_for(3ms); std::this_thread::sleep_for(6ms);
EXPECT_EQ(m_jobService->status().toStdString(), std::string{"running"}); EXPECT_EQ(m_jobService->status().toStdString(), std::string{"running"});
m_jobService->Suspend(); m_jobService->Suspend();
std::this_thread::sleep_for(1ms); std::this_thread::sleep_for(2ms);
EXPECT_EQ(m_jobService->status().toStdString(), std::string{"suspending"}); EXPECT_EQ(m_jobService->status().toStdString(), std::string{"suspending"});
std::this_thread::sleep_for(1ms); std::this_thread::sleep_for(2ms);
EXPECT_EQ(m_jobService->status().toStdString(), std::string{"suspended"}); EXPECT_EQ(m_jobService->status().toStdString(), std::string{"suspended"});
m_jobService->Resume(); m_jobService->Resume();
std::this_thread::sleep_for(1ms); std::this_thread::sleep_for(2ms);
EXPECT_EQ(m_jobService->status().toStdString(), std::string{"running"}); EXPECT_EQ(m_jobService->status().toStdString(), std::string{"running"});
EXPECT_TRUE(m_thread->wait()); EXPECT_TRUE(m_thread->wait());