Merge lp:~ted/ubuntu-app-launch/system-app-watch into lp:ubuntu-app-launch

Proposed by Ted Gould
Status: Merged
Approved by: Marcus Tomlinson
Approved revision: 340
Merged at revision: 311
Proposed branch: lp:~ted/ubuntu-app-launch/system-app-watch
Merge into: lp:ubuntu-app-launch
Prerequisite: lp:~ted/ubuntu-app-launch/registry-cleanup
Diff against target: 1009 lines (+694/-39)
16 files modified
libubuntu-app-launch/app-store-legacy.cpp (+172/-0)
libubuntu-app-launch/app-store-legacy.h (+14/-0)
libubuntu-app-launch/info-watcher.h (+14/-0)
libubuntu-app-launch/registry-impl.cpp (+40/-14)
libubuntu-app-launch/registry-impl.h (+17/-2)
libubuntu-app-launch/registry.cpp (+10/-0)
libubuntu-app-launch/registry.h (+19/-0)
tests/CMakeLists.txt (+10/-0)
tests/app-store-legacy.cpp (+155/-0)
tests/eventually-fixture.h (+76/-0)
tests/jobs-systemd.cpp (+2/-2)
tests/libual-cpp-test.cc (+43/-8)
tests/libual-test.cc (+2/-8)
tests/registry-mock.h (+13/-0)
tests/test-directory.h (+94/-0)
tools/ubuntu-app-watch.cpp (+13/-5)
To merge this branch: bzr merge lp:~ted/ubuntu-app-launch/system-app-watch
Reviewer Review Type Date Requested Status
Pete Woods (community) Approve
Marcus Tomlinson (community) Approve
unity-api-1-bot continuous-integration Needs Fixing
Review via email: mp+321241@code.launchpad.net

Commit message

Watch system folders for apps added and removed

Description of the change

This branch adds to signals, appAdded and appRemoved, and populates the backend for them with the legacy backend. It sets up file watches on the appropriate directories and then signals when things are changed.

Also it adds a bit to the testing framework to not wait forever on futures. Hopefully this will help some with tests timing out.

To post a comment you must log in.
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Marcus Tomlinson (marcustomlinson) wrote :

When trying to CMake with "-DCMAKE_BUILD_TYPE=coverage" I get the following errors (Have these tests since been removed?):

CMake Error at /usr/share/cmake/CoverageReport/EnableCoverageReport.cmake:91 (SET_PROPERTY):
  set_property could not find TARGET exec-util-test. Perhaps it has not yet
  been created.
Call Stack (most recent call first):
  CMakeLists.txt:131 (ENABLE_COVERAGE_REPORT)

CMake Error at /usr/share/cmake/CoverageReport/EnableCoverageReport.cmake:91 (SET_PROPERTY):
  set_property could not find TARGET failure-test. Perhaps it has not yet
  been created.
Call Stack (most recent call first):
  CMakeLists.txt:131 (ENABLE_COVERAGE_REPORT)

CMake Error at /usr/share/cmake/CoverageReport/EnableCoverageReport.cmake:91 (SET_PROPERTY):
  set_property could not find TARGET zg-test. Perhaps it has not yet been
  created.
Call Stack (most recent call first):
  CMakeLists.txt:131 (ENABLE_COVERAGE_REPORT)

Revision history for this message
Marcus Tomlinson (marcustomlinson) wrote :

The jobs-systems tests seem quite flaky. At least half the time I run them I get this mid-way through a test (no particular test, it varies from run to run):

systemd: Shutting down
DBus daemon: Shutdown

At this point the test process freezes. Looks like your test daemons are shutting down before the test is complete. Seen this at all?

Revision history for this message
Marcus Tomlinson (marcustomlinson) wrote :

Following from my last comment, I saw this same issue with libual-test (and I assume I'd probably see it with any other test using those test daemons). I restarted my machine and the tests began running smoother again. Zombie services hanging around perhaps? Sorry for the rambling, I don't just saying it as I see it.

Revision history for this message
Marcus Tomlinson (marcustomlinson) wrote :

While a brief scan of the code looks alright, I'd really like to run valgrind over the new code you've added to check the sanity of the memory handling.

I see that the bits you've added/changed to app-store-legacy.cpp, registry-impl.cpp, and registry.cpp are not covered in any tests. Would you be able to add some tests for these? Would be super handy! Also would be a shame to exclude this considering how good the coverage has been in this project thus far.

Revision history for this message
Marcus Tomlinson (marcustomlinson) wrote :

Changing to needs fixing.

review: Needs Fixing
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
334. By Ted Gould

Add handlers for app added and removed

335. By Ted Gould

C++ style

336. By Ted Gould

Split out the test directory helper

337. By Ted Gould

Add tests for the glue code in registry impl

Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

FAILED: Continuous integration, rev:335
https://jenkins.canonical.com/unity-api-1/job/lp-ubuntu-app-launch-ci/294/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build/1905/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/1912
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1694/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=zesty/1694/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1694
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1694/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=zesty/1694
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=zesty/1694/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/1694
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/1694/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=zesty/1694/console

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-ubuntu-app-launch-ci/294/rebuild

review: Needs Fixing (continuous-integration)
338. By Ted Gould

Forgot newlines

Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

FAILED: Continuous integration, rev:337
https://jenkins.canonical.com/unity-api-1/job/lp-ubuntu-app-launch-ci/295/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build/1906/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/1913
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1695
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1695/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=zesty/1695/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1695
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1695/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=zesty/1695
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=zesty/1695/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/1695/console
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=zesty/1695/console

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-ubuntu-app-launch-ci/295/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
339. By Ted Gould

Registry changes

Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
340. By Ted Gould

Fix the tests too

Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

FAILED: Continuous integration, rev:340
https://jenkins.canonical.com/unity-api-1/job/lp-ubuntu-app-launch-ci/300/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build/1911/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/1918
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1700
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1700/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=zesty/1700/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1700
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1700/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=zesty/1700/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/1700
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/1700/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=zesty/1700
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=zesty/1700/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-ubuntu-app-launch-ci/300/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Marcus Tomlinson (marcustomlinson) wrote :

+1

review: Approve
Revision history for this message
Pete Woods (pete-woods) wrote :

WOrks for me on the zesty u8 session.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'libubuntu-app-launch/app-store-legacy.cpp'
--- libubuntu-app-launch/app-store-legacy.cpp 2017-04-04 06:03:50 +0000
+++ libubuntu-app-launch/app-store-legacy.cpp 2017-04-04 06:03:50 +0000
@@ -19,6 +19,7 @@
1919
20#include "app-store-legacy.h"20#include "app-store-legacy.h"
21#include "application-impl-legacy.h"21#include "application-impl-legacy.h"
22#include "registry-impl.h"
22#include "string-util.h"23#include "string-util.h"
2324
24#include <regex>25#include <regex>
@@ -192,6 +193,177 @@
192 return std::make_shared<app_impls::Legacy>(appid.appname, getReg());193 return std::make_shared<app_impls::Legacy>(appid.appname, getReg());
193}194}
194195
196/** Turns a directory changed event from a file monitor into an
197 * internal signal. Makes sure we can deal with it first, and
198 * then propegates up the stack. */
199void Legacy::directoryChanged(GFile* file, GFileMonitorEvent type)
200{
201 g_debug("Getting event for '%s'", unique_gchar(g_file_get_path(file)).get());
202
203 auto filetype = g_file_query_file_type(file, G_FILE_QUERY_INFO_NONE, nullptr);
204 if (filetype != G_FILE_TYPE_REGULAR && filetype != G_FILE_TYPE_UNKNOWN)
205 {
206 g_debug("\tNot a regular file");
207 return;
208 }
209
210 auto cdesktopname = unique_gchar(g_file_get_basename(file));
211 if (!cdesktopname)
212 {
213 g_debug("\tNo basename");
214 return;
215 }
216 std::string desktopname{cdesktopname.get()};
217
218 std::string appname;
219 std::smatch match;
220 if (std::regex_match(desktopname, match, desktop_remover))
221 {
222 appname = match[1].str();
223 }
224 else
225 {
226 return;
227 }
228
229 auto reg = getReg();
230
231 switch (type)
232 {
233 case G_FILE_MONITOR_EVENT_CREATED:
234 {
235 auto app = std::make_shared<app_impls::Legacy>(AppID::AppName::from_raw(appname), reg);
236
237 appAdded_(app);
238 break;
239 }
240 case G_FILE_MONITOR_EVENT_CHANGED:
241 {
242 auto app = std::make_shared<app_impls::Legacy>(AppID::AppName::from_raw(appname), reg);
243
244 infoChanged_(app);
245 break;
246 }
247 case G_FILE_MONITOR_EVENT_DELETED:
248 {
249 AppID appid{AppID::Package::from_raw({}), AppID::AppName::from_raw(appname), AppID::Version::from_raw({})};
250 if (verifyAppname(appid.package, appid.appname))
251 {
252 /* Check to see if we've got a shadow situation and we
253 * can still build this app */
254 auto app = std::make_shared<app_impls::Legacy>(AppID::AppName::from_raw(appname), reg);
255 infoChanged_(app);
256 }
257 else
258 {
259 appRemoved_(appid);
260 }
261 break;
262 }
263 default:
264 break;
265 };
266}
267
268/** Function that setups file monitors on all of the system application
269 * directories and the user application directory. Any time an application
270 * is added or removed or changed we send the appropriate signal up the
271 * stack. */
272void Legacy::setupMonitors()
273{
274 std::call_once(monitorsSetup_, [this]() {
275 auto reg = getReg();
276 monitors_ =
277 reg->thread.executeOnThread<std::set<std::unique_ptr<GFileMonitor, unity::util::GObjectDeleter>>>([this]() {
278 std::set<std::unique_ptr<GFileMonitor, unity::util::GObjectDeleter>> monitors;
279
280 auto monitorDir = [this](const gchar* dirname) {
281 auto appdir = unique_gchar(g_build_filename(dirname, "applications", nullptr));
282 auto gfile = unity::util::unique_gobject(g_file_new_for_path(appdir.get()));
283
284 if (!g_file_query_exists(gfile.get(), nullptr))
285 {
286 throw std::runtime_error{std::string{"Directory '"} + appdir.get() + "' doesn't exist"};
287 }
288
289 if (g_file_query_file_type(gfile.get(), G_FILE_QUERY_INFO_NONE, nullptr) != G_FILE_TYPE_DIRECTORY)
290 {
291 throw std::runtime_error{std::string{"'"} + appdir.get() + "' is not a directory"};
292 }
293
294 GError* error = nullptr;
295 auto monitor = unity::util::unique_gobject(
296 g_file_monitor_directory(gfile.get(), G_FILE_MONITOR_NONE, nullptr, &error));
297
298 if (error != nullptr)
299 {
300 std::string message = std::string{"Unable to create file monitor: "} + error->message;
301 g_error_free(error);
302 throw std::runtime_error{message};
303 }
304
305 g_signal_connect(
306 monitor.get(), "changed",
307 G_CALLBACK(+[](GFileMonitor*, GFile* file, GFile*, GFileMonitorEvent type, gpointer user_data) {
308 auto pthis = static_cast<Legacy*>(user_data);
309 pthis->directoryChanged(file, type);
310 }),
311 this);
312
313 return monitor;
314 };
315
316 auto dirs = g_get_system_data_dirs();
317 for (int i = 0; dirs != nullptr && dirs[i] != nullptr; i++)
318 {
319 try
320 {
321 monitors.insert(monitorDir(dirs[i]));
322 }
323 catch (std::runtime_error& e)
324 {
325 g_debug("Unable to create directory monitor for system dir '%s': %s", dirs[i], e.what());
326 }
327 }
328
329 try
330 {
331 monitors.insert(monitorDir(g_get_user_data_dir()));
332 }
333 catch (std::runtime_error& e)
334 {
335 g_debug("Unable to create directory monitor for user data dir: %s", e.what());
336 }
337
338 return monitors;
339 });
340 });
341}
342
343/** Return the signal object, but make sure we have the
344 * monitors setup first */
345core::Signal<const std::shared_ptr<Application>&>& Legacy::infoChanged()
346{
347 setupMonitors();
348 return infoChanged_;
349}
350
351/** Return the signal object, but make sure we have the
352 * monitors setup first */
353core::Signal<const std::shared_ptr<Application>&>& Legacy::appAdded()
354{
355 setupMonitors();
356 return appAdded_;
357}
358
359/** Return the signal object, but make sure we have the
360 * monitors setup first */
361core::Signal<const AppID&>& Legacy::appRemoved()
362{
363 setupMonitors();
364 return appRemoved_;
365}
366
195} // namespace app_store367} // namespace app_store
196} // namespace app_launch368} // namespace app_launch
197} // namespace ubuntu369} // namespace ubuntu
198370
=== modified file 'libubuntu-app-launch/app-store-legacy.h'
--- libubuntu-app-launch/app-store-legacy.h 2017-04-04 06:03:50 +0000
+++ libubuntu-app-launch/app-store-legacy.h 2017-04-04 06:03:50 +0000
@@ -21,6 +21,8 @@
2121
22#include "app-store-base.h"22#include "app-store-base.h"
2323
24#include <unity/util/GObjectMemory.h>
25
24namespace ubuntu26namespace ubuntu
25{27{
26namespace app_launch28namespace app_launch
@@ -46,6 +48,18 @@
4648
47 /* Application Creation */49 /* Application Creation */
48 virtual std::shared_ptr<app_impls::Base> create(const AppID& appid) override;50 virtual std::shared_ptr<app_impls::Base> create(const AppID& appid) override;
51
52 /* Info watching */
53 virtual core::Signal<const std::shared_ptr<Application>&>& infoChanged() override;
54 virtual core::Signal<const std::shared_ptr<Application>&>& appAdded() override;
55 virtual core::Signal<const AppID&>& appRemoved() override;
56
57private:
58 std::set<std::unique_ptr<GFileMonitor, unity::util::GObjectDeleter>> monitors_;
59 std::once_flag monitorsSetup_;
60
61 void directoryChanged(GFile* file, GFileMonitorEvent type);
62 void setupMonitors();
49};63};
5064
51} // namespace app_store65} // namespace app_store
5266
=== modified file 'libubuntu-app-launch/info-watcher.h'
--- libubuntu-app-launch/info-watcher.h 2017-04-04 06:03:50 +0000
+++ libubuntu-app-launch/info-watcher.h 2017-04-04 06:03:50 +0000
@@ -43,9 +43,23 @@
43 return infoChanged_;43 return infoChanged_;
44 }44 }
4545
46 virtual core::Signal<const std::shared_ptr<Application>&>& appAdded()
47 {
48 return appAdded_;
49 }
50
51 virtual core::Signal<const AppID&>& appRemoved()
52 {
53 return appRemoved_;
54 }
55
46protected:56protected:
47 /** Signal for info changed on an application */57 /** Signal for info changed on an application */
48 core::Signal<const std::shared_ptr<Application>&> infoChanged_;58 core::Signal<const std::shared_ptr<Application>&> infoChanged_;
59 /** Signal for applications added */
60 core::Signal<const std::shared_ptr<Application>&> appAdded_;
61 /** Signal for applications removed */
62 core::Signal<const AppID&> appRemoved_;
4963
50 /** Accessor function to the registry that ensures we can still64 /** Accessor function to the registry that ensures we can still
51 get it, which we always should be able to, but in case. */65 get it, which we always should be able to, but in case. */
5266
=== modified file 'libubuntu-app-launch/registry-impl.cpp'
--- libubuntu-app-launch/registry-impl.cpp 2017-04-04 06:03:50 +0000
+++ libubuntu-app-launch/registry-impl.cpp 2017-04-04 06:03:50 +0000
@@ -171,25 +171,51 @@
171 return watchingAppStarting_;171 return watchingAppStarting_;
172}172}
173173
174/** Sets up the signals down to the info watchers and we aggregate
175 them up to users of UAL. We connect to all their signals and
176 pass them up. */
177void Registry::Impl::infoWatchersSetup()
178{
179 std::call_once(flag_infoWatchersSetup, [this] {
180 g_debug("Info watchers signals setup");
181
182 /* Grab all the app stores and the ZG info watcher */
183 std::list<std::shared_ptr<info_watcher::Base>> watchers{_appStores.begin(), _appStores.end()};
184 watchers.push_back(getZgWatcher());
185
186 /* Connect each of their signals to us, and track that connection */
187 for (const auto& watcher : watchers)
188 {
189 infoWatchers_.emplace_back(std::make_pair(
190 watcher,
191 infoWatcherConnections{
192 watcher->infoChanged().connect(
193 [this](const std::shared_ptr<Application>& app) { sig_appInfoUpdated(app); }),
194 watcher->appAdded().connect([this](const std::shared_ptr<Application>& app) { sig_appAdded(app); }),
195 watcher->appRemoved().connect([this](const AppID& appid) { sig_appRemoved(appid); }),
196 }));
197 }
198 });
199}
200
174core::Signal<const std::shared_ptr<Application>&>& Registry::Impl::appInfoUpdated()201core::Signal<const std::shared_ptr<Application>&>& Registry::Impl::appInfoUpdated()
175{202{
176 std::call_once(flag_appInfoUpdated, [this] {203 infoWatchersSetup();
177 g_debug("App Info Updated Signal Initialized");
178
179 std::list<std::shared_ptr<info_watcher::Base>> apps{_appStores.begin(), _appStores.end()};
180 apps.push_back(getZgWatcher());
181
182 for (const auto& app : apps)
183 {
184 infoWatchers_.emplace_back(
185 std::make_pair(app, app->infoChanged().connect([this](const std::shared_ptr<Application>& app) {
186 sig_appInfoUpdated(app);
187 })));
188 }
189 });
190 return sig_appInfoUpdated;204 return sig_appInfoUpdated;
191}205}
192206
207core::Signal<const std::shared_ptr<Application>&>& Registry::Impl::appAdded()
208{
209 infoWatchersSetup();
210 return sig_appAdded;
211}
212
213core::Signal<const AppID&>& Registry::Impl::appRemoved()
214{
215 infoWatchersSetup();
216 return sig_appRemoved;
217}
218
193std::shared_ptr<Application> Registry::Impl::createApp(const AppID& appid)219std::shared_ptr<Application> Registry::Impl::createApp(const AppID& appid)
194{220{
195 for (const auto& appStore : appStores())221 for (const auto& appStore : appStores())
196222
=== modified file 'libubuntu-app-launch/registry-impl.h'
--- libubuntu-app-launch/registry-impl.h 2017-04-04 06:03:50 +0000
+++ libubuntu-app-launch/registry-impl.h 2017-04-04 06:03:50 +0000
@@ -98,6 +98,8 @@
98 }98 }
9999
100 core::Signal<const std::shared_ptr<Application>&>& appInfoUpdated();100 core::Signal<const std::shared_ptr<Application>&>& appInfoUpdated();
101 core::Signal<const std::shared_ptr<Application>&>& appAdded();
102 core::Signal<const AppID&>& appRemoved();
101103
102 const std::list<std::shared_ptr<app_store::Base>>& appStores()104 const std::list<std::shared_ptr<app_store::Base>>& appStores()
103 {105 {
@@ -156,10 +158,23 @@
156158
157 /** Signal for application info changing */159 /** Signal for application info changing */
158 core::Signal<const std::shared_ptr<Application>&> sig_appInfoUpdated;160 core::Signal<const std::shared_ptr<Application>&> sig_appInfoUpdated;
161 /** Signal for applications added */
162 core::Signal<const std::shared_ptr<Application>&> sig_appAdded;
163 /** Signal for applications removed */
164 core::Signal<const AppID&> sig_appRemoved;
165
166 void infoWatchersSetup(const std::shared_ptr<Registry>& reg);
159 /** Flag to see if we've initialized the info watcher list */167 /** Flag to see if we've initialized the info watcher list */
160 std::once_flag flag_appInfoUpdated;168 std::once_flag flag_infoWatchersSetup;
169 struct infoWatcherConnections
170 {
171 core::ScopedConnection infoUpdated;
172 core::ScopedConnection appAdded;
173 core::ScopedConnection appRemoved;
174 };
161 /** List of info watchers along with a signal handle to our connection to their update signal */175 /** List of info watchers along with a signal handle to our connection to their update signal */
162 std::list<std::pair<std::shared_ptr<info_watcher::Base>, core::ScopedConnection>> infoWatchers_;176 std::list<std::pair<std::shared_ptr<info_watcher::Base>, infoWatcherConnections>> infoWatchers_;
177 void infoWatchersSetup();
163178
164 /** ZG Info Watcher */179 /** ZG Info Watcher */
165 std::shared_ptr<info_watcher::Zeitgeist> zgWatcher_;180 std::shared_ptr<info_watcher::Zeitgeist> zgWatcher_;
166181
=== modified file 'libubuntu-app-launch/registry.cpp'
--- libubuntu-app-launch/registry.cpp 2017-04-04 06:03:50 +0000
+++ libubuntu-app-launch/registry.cpp 2017-04-04 06:03:50 +0000
@@ -154,5 +154,15 @@
154 return reg->impl->appInfoUpdated();154 return reg->impl->appInfoUpdated();
155}155}
156156
157core::Signal<const std::shared_ptr<Application>&>& Registry::appAdded(const std::shared_ptr<Registry>& reg)
158{
159 return reg->impl->appAdded();
160}
161
162core::Signal<const AppID&>& Registry::appRemoved(const std::shared_ptr<Registry>& reg)
163{
164 return reg->impl->appRemoved();
165}
166
157} // namespace app_launch167} // namespace app_launch
158} // namespace ubuntu168} // namespace ubuntu
159169
=== modified file 'libubuntu-app-launch/registry.h'
--- libubuntu-app-launch/registry.h 2017-04-04 06:03:50 +0000
+++ libubuntu-app-launch/registry.h 2017-04-04 06:03:50 +0000
@@ -137,6 +137,25 @@
137 static core::Signal<const std::shared_ptr<Application>&>& appInfoUpdated(137 static core::Signal<const std::shared_ptr<Application>&>& appInfoUpdated(
138 const std::shared_ptr<Registry>& reg = getDefault());138 const std::shared_ptr<Registry>& reg = getDefault());
139139
140 /** Get the signal object that is signaled when there is a new application
141 that has been added to the system.
142
143 \note This signal handler is activated on the UAL thread
144
145 \param reg Registry to get the handler from
146 */
147 static core::Signal<const std::shared_ptr<Application>&>& appAdded(
148 const std::shared_ptr<Registry>& reg = getDefault());
149
150 /** Get the signal object that is signaled when an application is
151 removed from the system.
152
153 \note This signal handler is activated on the UAL thread
154
155 \param reg Registry to get the handler from
156 */
157 static core::Signal<const AppID&>& appRemoved(const std::shared_ptr<Registry>& reg = getDefault());
158
140 /** The Application Manager, almost always if you're not Unity8, don't159 /** The Application Manager, almost always if you're not Unity8, don't
141 use this API. Testing is a special case. Subclass this interface and160 use this API. Testing is a special case. Subclass this interface and
142 implement these functions.161 implement these functions.
143162
=== modified file 'tests/CMakeLists.txt'
--- tests/CMakeLists.txt 2017-03-14 16:46:00 +0000
+++ tests/CMakeLists.txt 2017-04-04 06:03:50 +0000
@@ -50,6 +50,15 @@
50add_test (NAME libual-test COMMAND libual-test)50add_test (NAME libual-test COMMAND libual-test)
51add_test (NAME libual-cpp-test COMMAND libual-cpp-test)51add_test (NAME libual-cpp-test COMMAND libual-cpp-test)
5252
53# App Store Legacy
54
55add_executable (app-store-legacy
56 app-store-legacy.cpp)
57target_link_libraries (app-store-legacy ${GMOCK_LIBRARIES} ${GTEST_MAIN_LIBRARIES} launcher-static ${DBUSTEST_LIBRARIES})
58
59add_test(NAME app-store-legacy COMMAND "${CMAKE_CURRENT_BINARY_DIR}/app-store-legacy" --gtest_list_tests "|" grep "\"^ \"" "|" xargs -n 1 printf "\"--gtest_filter=*.%s\\n\"" "|" xargs -n 1 "${CMAKE_CURRENT_BINARY_DIR}/app-store-legacy")
60
61
53# Jobs Base Test62# Jobs Base Test
5463
55add_executable (jobs-base-test64add_executable (jobs-base-test
@@ -129,6 +138,7 @@
129add_custom_target(format-tests138add_custom_target(format-tests
130 COMMAND clang-format -i -style=file139 COMMAND clang-format -i -style=file
131 application-info-desktop.cpp140 application-info-desktop.cpp
141 app-store-legacy.cpp
132 libual-cpp-test.cc142 libual-cpp-test.cc
133 libual-test.cc143 libual-test.cc
134 list-apps.cpp144 list-apps.cpp
135145
=== added file 'tests/app-store-legacy.cpp'
--- tests/app-store-legacy.cpp 1970-01-01 00:00:00 +0000
+++ tests/app-store-legacy.cpp 2017-04-04 06:03:50 +0000
@@ -0,0 +1,155 @@
1/*
2 * Copyright © 2017 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Ted Gould <ted.gould@canonical.com>
18 */
19
20#include "app-store-legacy.h"
21
22#include "eventually-fixture.h"
23#include "registry-mock.h"
24#include "test-directory.h"
25#include <gmock/gmock.h>
26#include <gtest/gtest.h>
27#include <libdbustest/dbus-test.h>
28#include <unity/util/GObjectMemory.h>
29#include <unity/util/GlibMemory.h>
30
31class AppStoreLegacy : public EventuallyFixture
32{
33protected:
34 std::unique_ptr<DbusTestService, unity::util::GObjectDeleter> service;
35 std::shared_ptr<RegistryMock> registry;
36
37 virtual void SetUp()
38 {
39 setenv("XDG_DATA_DIRS", CMAKE_SOURCE_DIR, 1);
40
41 service = unity::util::unique_gobject(dbus_test_service_new(nullptr));
42 dbus_test_service_start_tasks(service.get());
43 registry = std::make_shared<RegistryMock>(std::list<std::shared_ptr<ubuntu::app_launch::app_store::Base>>{},
44 std::shared_ptr<ubuntu::app_launch::jobs::manager::Base>{});
45 }
46};
47
48TEST_F(AppStoreLegacy, Init)
49{
50 auto store = std::make_shared<ubuntu::app_launch::app_store::Legacy>(registry->impl);
51 store.reset();
52}
53
54TEST_F(AppStoreLegacy, FindApp)
55{
56 TestDirectory testdir;
57 testdir.addApp("testapp",
58 {{G_KEY_FILE_DESKTOP_GROUP,
59 {
60 {G_KEY_FILE_DESKTOP_KEY_NAME, "Test App"},
61 {G_KEY_FILE_DESKTOP_KEY_TYPE, "Application"},
62 {G_KEY_FILE_DESKTOP_KEY_ICON, "foo.png"},
63 {G_KEY_FILE_DESKTOP_KEY_EXEC, "foo"},
64 }}});
65
66 auto store = std::make_shared<ubuntu::app_launch::app_store::Legacy>(registry->impl);
67
68 EXPECT_TRUE(store->verifyAppname(ubuntu::app_launch::AppID::Package::from_raw({}),
69 ubuntu::app_launch::AppID::AppName::from_raw("testapp")));
70}
71
72TEST_F(AppStoreLegacy, RemoveApp)
73{
74 TestDirectory testdir;
75 testdir.addApp("testapp",
76 {{G_KEY_FILE_DESKTOP_GROUP,
77 {
78 {G_KEY_FILE_DESKTOP_KEY_NAME, "Test App"},
79 {G_KEY_FILE_DESKTOP_KEY_TYPE, "Application"},
80 {G_KEY_FILE_DESKTOP_KEY_ICON, "foo.png"},
81 {G_KEY_FILE_DESKTOP_KEY_EXEC, "foo"},
82 }}});
83
84 auto store = std::make_shared<ubuntu::app_launch::app_store::Legacy>(registry->impl);
85
86 std::promise<std::string> removedAppId;
87 store->appRemoved().connect([&](const ubuntu::app_launch::AppID &appid) { removedAppId.set_value(appid); });
88
89 testdir.removeApp("testapp");
90
91 EXPECT_EVENTUALLY_FUTURE_EQ(std::string{"testapp"}, removedAppId.get_future());
92}
93
94TEST_F(AppStoreLegacy, AddedApp)
95{
96 TestDirectory testdir;
97 auto store = std::make_shared<ubuntu::app_launch::app_store::Legacy>(registry->impl);
98
99 std::promise<std::string> addedAppId;
100 store->appAdded().connect(
101 [&](const std::shared_ptr<ubuntu::app_launch::Application> &app) { addedAppId.set_value(app->appId()); });
102
103 testdir.addApp("testapp",
104 {{G_KEY_FILE_DESKTOP_GROUP,
105 {
106 {G_KEY_FILE_DESKTOP_KEY_NAME, "Test App"},
107 {G_KEY_FILE_DESKTOP_KEY_TYPE, "Application"},
108 {G_KEY_FILE_DESKTOP_KEY_ICON, "foo.png"},
109 {G_KEY_FILE_DESKTOP_KEY_EXEC, "foo"},
110 }}});
111
112 EXPECT_EVENTUALLY_FUTURE_EQ(std::string{"testapp"}, addedAppId.get_future());
113}
114
115TEST_F(AppStoreLegacy, ShadowDelete)
116{
117 TestDirectory testdir;
118 testdir.addApp("testapp",
119 {{G_KEY_FILE_DESKTOP_GROUP,
120 {
121 {G_KEY_FILE_DESKTOP_KEY_NAME, "Test App"},
122 {G_KEY_FILE_DESKTOP_KEY_TYPE, "Application"},
123 {G_KEY_FILE_DESKTOP_KEY_ICON, "foo.png"},
124 {G_KEY_FILE_DESKTOP_KEY_EXEC, "foo"},
125 }}});
126
127 TestDirectory testdir2;
128 testdir2.addApp("testapp",
129 {{G_KEY_FILE_DESKTOP_GROUP,
130 {
131 {G_KEY_FILE_DESKTOP_KEY_NAME, "Test App"},
132 {G_KEY_FILE_DESKTOP_KEY_TYPE, "Application"},
133 {G_KEY_FILE_DESKTOP_KEY_ICON, "foo.png"},
134 {G_KEY_FILE_DESKTOP_KEY_EXEC, "foo"},
135 }}});
136
137 auto store = std::make_shared<ubuntu::app_launch::app_store::Legacy>(registry->impl);
138
139 std::promise<std::string> updatedAppId;
140 store->infoChanged().connect(
141 [&](const std::shared_ptr<ubuntu::app_launch::Application> &app) { updatedAppId.set_value(app->appId()); });
142
143 std::promise<std::string> deleteAppId;
144 store->appRemoved().connect([&](const ubuntu::app_launch::AppID &appid) { deleteAppId.set_value(appid); });
145 std::shared_future<std::string> deleteFuture = deleteAppId.get_future();
146
147 testdir.removeApp("testapp");
148
149 EXPECT_EVENTUALLY_FUTURE_EQ(std::string{"testapp"}, updatedAppId.get_future());
150 EXPECT_NE(std::future_status::ready, deleteFuture.wait_for(std::chrono::seconds{0}));
151
152 testdir2.removeApp("testapp");
153
154 EXPECT_EVENTUALLY_FUTURE_EQ(std::string{"testapp"}, deleteFuture);
155}
0156
=== modified file 'tests/eventually-fixture.h'
--- tests/eventually-fixture.h 2017-01-18 20:43:25 +0000
+++ tests/eventually-fixture.h 2017-04-04 06:03:50 +0000
@@ -118,6 +118,37 @@
118 return eventuallyLoop(func); \118 return eventuallyLoop(func); \
119 }119 }
120120
121#define _EVENTUALLY_FUTURE_HELPER(oper) \
122 template <typename comptype> \
123 testing::AssertionResult eventuallyFutureHelper##oper(const char *desca, const char *descb, comptype expected, \
124 std::future<comptype> future) \
125 { \
126 std::function<testing::AssertionResult(void)> func = [&]() { \
127 auto status = future.wait_for(std::chrono::seconds{0}); \
128 if (status != std::future_status::ready) \
129 { \
130 return testing::AssertionFailure(); \
131 } \
132 return testing::internal::CmpHelper##oper(desca, descb, expected, future.get()); \
133 }; \
134 return eventuallyLoop(func); \
135 } \
136 \
137 template <typename comptype> \
138 testing::AssertionResult eventuallyFutureHelper##oper(const char *desca, const char *descb, comptype expected, \
139 std::shared_future<comptype> future) \
140 { \
141 std::function<testing::AssertionResult(void)> func = [&]() { \
142 auto status = future.wait_for(std::chrono::seconds{0}); \
143 if (status != std::future_status::ready) \
144 { \
145 return testing::AssertionFailure(); \
146 } \
147 return testing::internal::CmpHelper##oper(desca, descb, expected, future.get()); \
148 }; \
149 return eventuallyLoop(func); \
150 }
151
121 _EVENTUALLY_HELPER(EQ);152 _EVENTUALLY_HELPER(EQ);
122 _EVENTUALLY_HELPER(NE);153 _EVENTUALLY_HELPER(NE);
123 _EVENTUALLY_HELPER(LT);154 _EVENTUALLY_HELPER(LT);
@@ -132,8 +163,16 @@
132 _EVENTUALLY_FUNC_HELPER(STREQ);163 _EVENTUALLY_FUNC_HELPER(STREQ);
133 _EVENTUALLY_FUNC_HELPER(STRNE);164 _EVENTUALLY_FUNC_HELPER(STRNE);
134165
166 _EVENTUALLY_FUTURE_HELPER(EQ);
167 _EVENTUALLY_FUTURE_HELPER(NE);
168 _EVENTUALLY_FUTURE_HELPER(LT);
169 _EVENTUALLY_FUTURE_HELPER(GT);
170 _EVENTUALLY_FUTURE_HELPER(STREQ);
171 _EVENTUALLY_FUTURE_HELPER(STRNE);
172
135#undef _EVENTUALLY_HELPER173#undef _EVENTUALLY_HELPER
136#undef _EVENTUALLY_FUNC_HELPER174#undef _EVENTUALLY_FUNC_HELPER
175#undef _EVENTUALLY_FUTURE_HELPER
137};176};
138177
139/* Helpers */178/* Helpers */
@@ -209,3 +248,40 @@
209248
210#define ASSERT_EVENTUALLY_FUNC_STRNE(expected, actual) \249#define ASSERT_EVENTUALLY_FUNC_STRNE(expected, actual) \
211 ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyFuncHelperSTRNE, expected, actual)250 ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyFuncHelperSTRNE, expected, actual)
251
252/* Future Helpers */
253#define EXPECT_EVENTUALLY_FUTURE_EQ(expected, actual) \
254 EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperEQ, expected, actual)
255
256#define EXPECT_EVENTUALLY_FUTURE_NE(expected, actual) \
257 EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperNE, expected, actual)
258
259#define EXPECT_EVENTUALLY_FUTURE_LT(expected, actual) \
260 EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperLT, expected, actual)
261
262#define EXPECT_EVENTUALLY_FUTURE_GT(expected, actual) \
263 EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperGT, expected, actual)
264
265#define EXPECT_EVENTUALLY_FUTURE_STREQ(expected, actual) \
266 EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperSTREQ, expected, actual)
267
268#define EXPECT_EVENTUALLY_FUTURE_STRNE(expected, actual) \
269 EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperSTRNE, expected, actual)
270
271#define ASSERT_EVENTUALLY_FUTURE_EQ(expected, actual) \
272 ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperEQ, expected, actual)
273
274#define ASSERT_EVENTUALLY_FUTURE_NE(expected, actual) \
275 ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperNE, expected, actual)
276
277#define ASSERT_EVENTUALLY_FUTURE_LT(expected, actual) \
278 ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperLT, expected, actual)
279
280#define ASSERT_EVENTUALLY_FUTURE_GT(expected, actual) \
281 ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperGT, expected, actual)
282
283#define ASSERT_EVENTUALLY_FUTURE_STREQ(expected, actual) \
284 ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperSTREQ, expected, actual)
285
286#define ASSERT_EVENTUALLY_FUTURE_STRNE(expected, actual) \
287 ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperSTRNE, expected, actual)
212288
=== modified file 'tests/jobs-systemd.cpp'
--- tests/jobs-systemd.cpp 2017-04-04 06:03:50 +0000
+++ tests/jobs-systemd.cpp 2017-04-04 06:03:50 +0000
@@ -326,7 +326,7 @@
326 {defaultJobName(), std::string{multipleAppID()}, "1234", 1, {}}),326 {defaultJobName(), std::string{multipleAppID()}, "1234", 1, {}}),
327 "/foo");327 "/foo");
328328
329 EXPECT_EQ(multipleAppID(), newunit.get_future().get());329 EXPECT_EVENTUALLY_FUTURE_EQ(multipleAppID(), newunit.get_future());
330}330}
331331
332TEST_F(JobsSystemd, SignalRemove)332TEST_F(JobsSystemd, SignalRemove)
@@ -362,7 +362,7 @@
362 {defaultJobName(), std::string{multipleAppID()}, "1234567890", 1, {}}),362 {defaultJobName(), std::string{multipleAppID()}, "1234567890", 1, {}}),
363 "/foo");363 "/foo");
364364
365 EXPECT_EQ(multipleAppID(), removeunit.get_future().get());365 EXPECT_EVENTUALLY_FUTURE_EQ(multipleAppID(), removeunit.get_future());
366}366}
367367
368TEST_F(JobsSystemd, UnitFailure)368TEST_F(JobsSystemd, UnitFailure)
369369
=== modified file 'tests/libual-cpp-test.cc'
--- tests/libual-cpp-test.cc 2017-04-04 06:03:50 +0000
+++ tests/libual-cpp-test.cc 2017-04-04 06:03:50 +0000
@@ -44,6 +44,7 @@
44#include "snapd-mock.h"44#include "snapd-mock.h"
45#include "spew-master.h"45#include "spew-master.h"
46#include "systemd-mock.h"46#include "systemd-mock.h"
47#include "test-directory.h"
47#include "zg-mock.h"48#include "zg-mock.h"
4849
49#define LOCAL_SNAPD_TEST_SOCKET (SNAPD_TEST_SOCKET "-libual-cpp-test")50#define LOCAL_SNAPD_TEST_SOCKET (SNAPD_TEST_SOCKET "-libual-cpp-test")
@@ -1154,6 +1155,46 @@
1154 g_spawn_command_line_sync("rm -rf " CMAKE_BINARY_DIR "/libual-proc", NULL, NULL, NULL, NULL);1155 g_spawn_command_line_sync("rm -rf " CMAKE_BINARY_DIR "/libual-proc", NULL, NULL, NULL, NULL);
1155}1156}
11561157
1158TEST_F(LibUAL, AppInfoSignals)
1159{
1160 /* Setup the stores mock */
1161 auto mockstore = std::make_shared<MockStore>(registry->impl);
1162 registry =
1163 std::make_shared<RegistryMock>(std::list<std::shared_ptr<ubuntu::app_launch::app_store::Base>>{mockstore},
1164 std::shared_ptr<ubuntu::app_launch::jobs::manager::Base>{});
1165
1166 /* Build an app */
1167 auto singleappid = ubuntu::app_launch::AppID::find(registry, "single");
1168 auto myapp = std::make_shared<MockApp>(singleappid, registry->impl);
1169
1170 /* Setup an app added signal handler */
1171 std::promise<ubuntu::app_launch::AppID> addedAppId;
1172 ubuntu::app_launch::Registry::appAdded(registry).connect(
1173 [&](const std::shared_ptr<ubuntu::app_launch::Application>& app) { addedAppId.set_value(app->appId()); });
1174
1175 mockstore->mock_signalAppAdded(myapp);
1176
1177 EXPECT_EVENTUALLY_FUTURE_EQ(singleappid, addedAppId.get_future());
1178
1179 /* Setup an info changed signal handler */
1180 std::promise<ubuntu::app_launch::AppID> changedAppId;
1181 ubuntu::app_launch::Registry::appInfoUpdated(registry).connect(
1182 [&](const std::shared_ptr<ubuntu::app_launch::Application>& app) { changedAppId.set_value(app->appId()); });
1183
1184 mockstore->mock_signalAppInfoChanged(myapp);
1185
1186 EXPECT_EVENTUALLY_FUTURE_EQ(singleappid, changedAppId.get_future());
1187
1188 /* Setup an app removed signal handler */
1189 std::promise<ubuntu::app_launch::AppID> removedAppId;
1190 ubuntu::app_launch::Registry::appRemoved(registry).connect(
1191 [&](const ubuntu::app_launch::AppID& appid) { removedAppId.set_value(appid); });
1192
1193 mockstore->mock_signalAppRemoved(singleappid);
1194
1195 EXPECT_EVENTUALLY_FUTURE_EQ(singleappid, removedAppId.get_future());
1196}
1197
1157TEST_F(LibUAL, OOMSet)1198TEST_F(LibUAL, OOMSet)
1158{1199{
1159 g_setenv("UBUNTU_APP_LAUNCH_OOM_PROC_PATH", CMAKE_BINARY_DIR "/libual-proc", 1);1200 g_setenv("UBUNTU_APP_LAUNCH_OOM_PROC_PATH", CMAKE_BINARY_DIR "/libual-proc", 1);
@@ -1277,13 +1318,7 @@
1277 });1318 });
1278 t.detach();1319 t.detach();
12791320
1280 auto outputfuture = outputpromise.get_future();1321 EXPECT_EVENTUALLY_FUTURE_EQ(std::string{filedata}, outputpromise.get_future());
1281 while (outputfuture.wait_for(std::chrono::milliseconds{1}) != std::future_status::ready)
1282 {
1283 pause();
1284 }
1285
1286 ASSERT_STREQ(filedata, outputfuture.get().c_str());
12871322
1288 return;1323 return;
1289}1324}
@@ -1376,7 +1411,7 @@
1376 std::vector<std::string> execList{"Foo", "Bar", "Really really really long value", "Another value"};1411 std::vector<std::string> execList{"Foo", "Bar", "Really really really long value", "Another value"};
1377 ubuntu::app_launch::Helper::setExec(execList);1412 ubuntu::app_launch::Helper::setExec(execList);
13781413
1379 EXPECT_EQ(execList, socketpromise.get_future().get());1414 EXPECT_EVENTUALLY_FUTURE_EQ(execList, socketpromise.get_future());
1380}1415}
13811416
1382TEST_F(LibUAL, AppInfo)1417TEST_F(LibUAL, AppInfo)
13831418
=== modified file 'tests/libual-test.cc'
--- tests/libual-test.cc 2017-03-20 15:21:13 +0000
+++ tests/libual-test.cc 2017-04-04 06:03:50 +0000
@@ -892,13 +892,7 @@
892 });892 });
893 t.detach();893 t.detach();
894894
895 auto outputfuture = outputpromise.get_future();895 EXPECT_EVENTUALLY_FUTURE_EQ(std::string{filedata}, outputpromise.get_future());
896 while (outputfuture.wait_for(std::chrono::milliseconds{1}) != std::future_status::ready)
897 {
898 pause();
899 }
900
901 ASSERT_STREQ(filedata, outputfuture.get().c_str());
902896
903 return;897 return;
904}898}
@@ -1002,7 +996,7 @@
1002 .c_str(),996 .c_str(),
1003 nullptr);997 nullptr);
1004998
1005 EXPECT_EQ(execList, socketpromise.get_future().get());999 EXPECT_EVENTUALLY_FUTURE_EQ(execList, socketpromise.get_future());
1006}1000}
10071001
1008TEST_F(LibUAL, AppInfo)1002TEST_F(LibUAL, AppInfo)
10091003
=== modified file 'tests/registry-mock.h'
--- tests/registry-mock.h 2017-04-04 06:03:50 +0000
+++ tests/registry-mock.h 2017-04-04 06:03:50 +0000
@@ -54,6 +54,19 @@
5454
55 /* Application Creation */55 /* Application Creation */
56 MOCK_METHOD1(create, std::shared_ptr<ubuntu::app_launch::app_impls::Base>(const ubuntu::app_launch::AppID&));56 MOCK_METHOD1(create, std::shared_ptr<ubuntu::app_launch::app_impls::Base>(const ubuntu::app_launch::AppID&));
57
58 void mock_signalAppAdded(const std::shared_ptr<ubuntu::app_launch::Application>& app)
59 {
60 appAdded_(app);
61 }
62 void mock_signalAppRemoved(const ubuntu::app_launch::AppID& appid)
63 {
64 appRemoved_(appid);
65 }
66 void mock_signalAppInfoChanged(const std::shared_ptr<ubuntu::app_launch::Application>& app)
67 {
68 infoChanged_(app);
69 }
57};70};
5871
59class MockApp : public ubuntu::app_launch::app_impls::Base72class MockApp : public ubuntu::app_launch::app_impls::Base
6073
=== added file 'tests/test-directory.h'
--- tests/test-directory.h 1970-01-01 00:00:00 +0000
+++ tests/test-directory.h 2017-04-04 06:03:50 +0000
@@ -0,0 +1,94 @@
1/*
2 * Copyright © 2017 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Ted Gould <ted.gould@canonical.com>
18 */
19
20#include <unity/util/GlibMemory.h>
21#include <string>
22
23class TestDirectory
24{
25 std::string dirname_;
26 std::string appdir_;
27
28public:
29 TestDirectory()
30 {
31 GError *error{nullptr};
32
33 auto dirname = ubuntu::app_launch::unique_gchar(g_dir_make_tmp("xdg-data-tmp-XXXXXX", &error));
34 if (error != nullptr)
35 {
36 auto message = std::string{"Unable to create temporary directory: "} + error->message;
37 g_error_free(error);
38 throw std::runtime_error{message};
39 }
40 dirname_ = dirname.get();
41 g_debug("Setting temp XDG_DATA directory: %s", dirname.get());
42
43 appdir_ = ubuntu::app_launch::unique_gchar(g_build_filename(dirname.get(), "applications", nullptr)).get();
44 g_mkdir_with_parents(appdir_.c_str(), 0700);
45
46 auto datadirs =
47 ubuntu::app_launch::unique_gchar(g_strdup_printf("%s:%s", dirname.get(), g_getenv("XDG_DATA_DIRS")));
48 setenv("XDG_DATA_DIRS", datadirs.get(), 1);
49 }
50
51 ~TestDirectory()
52 {
53 auto command = ubuntu::app_launch::unique_gchar(g_strdup_printf("rm -rf %s", dirname_.c_str()));
54 g_spawn_command_line_sync(command.get(), nullptr, nullptr, nullptr, nullptr);
55 g_debug("Removing test directory: %s", dirname_.c_str());
56 }
57
58 void addApp(const std::string &appname,
59 const std::list<std::pair<std::string, std::list<std::pair<std::string, std::string>>>> &keydata)
60 {
61 auto keyfile = unity::util::unique_glib(g_key_file_new());
62
63 for (const auto &groupset : keydata)
64 {
65 auto groupname = groupset.first;
66 for (const auto &dataset : groupset.second)
67 {
68 auto key = dataset.first;
69 auto value = dataset.second;
70
71 g_key_file_set_string(keyfile.get(), groupname.c_str(), key.c_str(), value.c_str());
72 }
73 }
74
75 auto path = ubuntu::app_launch::unique_gchar(
76 g_build_filename(appdir_.c_str(), (appname + ".desktop").c_str(), nullptr));
77 GError *error{nullptr};
78
79 g_key_file_save_to_file(keyfile.get(), path.get(), &error);
80 if (error != nullptr)
81 {
82 auto message = std::string{"Unable to write desktop file for '"} + appname + "': " + error->message;
83 g_error_free(error);
84 throw std::runtime_error{message};
85 }
86 }
87
88 void removeApp(const std::string &appname)
89 {
90 auto path = ubuntu::app_launch::unique_gchar(
91 g_build_filename(appdir_.c_str(), (appname + ".desktop").c_str(), nullptr));
92 unlink(path.get());
93 }
94};
095
=== modified file 'tools/ubuntu-app-watch.cpp'
--- tools/ubuntu-app-watch.cpp 2017-02-08 17:34:52 +0000
+++ tools/ubuntu-app-watch.cpp 2017-04-04 06:03:50 +0000
@@ -29,16 +29,16 @@
2929
30 registry.appStarted().connect([](const std::shared_ptr<ubuntu::app_launch::Application>& app,30 registry.appStarted().connect([](const std::shared_ptr<ubuntu::app_launch::Application>& app,
31 const std::shared_ptr<ubuntu::app_launch::Application::Instance>& instance) {31 const std::shared_ptr<ubuntu::app_launch::Application::Instance>& instance) {
32 std::cout << "Started: " << (std::string)app->appId() << std::endl;32 std::cout << "Started: " << std::string{app->appId()} << std::endl;
33 });33 });
34 registry.appStopped().connect([](const std::shared_ptr<ubuntu::app_launch::Application>& app,34 registry.appStopped().connect([](const std::shared_ptr<ubuntu::app_launch::Application>& app,
35 const std::shared_ptr<ubuntu::app_launch::Application::Instance>& instance) {35 const std::shared_ptr<ubuntu::app_launch::Application::Instance>& instance) {
36 std::cout << "Stopped: " << (std::string)app->appId() << std::endl;36 std::cout << "Stopped: " << std::string{app->appId()} << std::endl;
37 });37 });
38 registry.appPaused().connect([](const std::shared_ptr<ubuntu::app_launch::Application>& app,38 registry.appPaused().connect([](const std::shared_ptr<ubuntu::app_launch::Application>& app,
39 const std::shared_ptr<ubuntu::app_launch::Application::Instance>& instance,39 const std::shared_ptr<ubuntu::app_launch::Application::Instance>& instance,
40 const std::vector<pid_t>& pids) {40 const std::vector<pid_t>& pids) {
41 std::cout << "Paused: " << (std::string)app->appId() << " (";41 std::cout << "Paused: " << std::string{app->appId()} << " (";
4242
43 for (auto pid : pids)43 for (auto pid : pids)
44 {44 {
@@ -50,7 +50,7 @@
50 registry.appResumed().connect([](const std::shared_ptr<ubuntu::app_launch::Application>& app,50 registry.appResumed().connect([](const std::shared_ptr<ubuntu::app_launch::Application>& app,
51 const std::shared_ptr<ubuntu::app_launch::Application::Instance>& instance,51 const std::shared_ptr<ubuntu::app_launch::Application::Instance>& instance,
52 const std::vector<pid_t>& pids) {52 const std::vector<pid_t>& pids) {
53 std::cout << "Resumed: " << (std::string)app->appId() << " (";53 std::cout << "Resumed: " << std::string{app->appId()} << " (";
5454
55 for (auto pid : pids)55 for (auto pid : pids)
56 {56 {
@@ -62,7 +62,7 @@
62 registry.appFailed().connect([](const std::shared_ptr<ubuntu::app_launch::Application>& app,62 registry.appFailed().connect([](const std::shared_ptr<ubuntu::app_launch::Application>& app,
63 const std::shared_ptr<ubuntu::app_launch::Application::Instance>& instance,63 const std::shared_ptr<ubuntu::app_launch::Application::Instance>& instance,
64 ubuntu::app_launch::Registry::FailureType type) {64 ubuntu::app_launch::Registry::FailureType type) {
65 std::cout << "Failed: " << (std::string)app->appId();65 std::cout << "Failed: " << std::string{app->appId()};
66 switch (type)66 switch (type)
67 {67 {
68 case ubuntu::app_launch::Registry::FailureType::CRASH:68 case ubuntu::app_launch::Registry::FailureType::CRASH:
@@ -74,6 +74,14 @@
74 }74 }
75 std::cout << std::endl;75 std::cout << std::endl;
76 });76 });
77 registry.appAdded().connect([](const std::shared_ptr<ubuntu::app_launch::Application>& app) {
78 std::cout << "Added: " << std::string{app->appId()} << std::endl;
79 });
80 registry.appRemoved().connect(
81 [](const ubuntu::app_launch::AppID& appid) { std::cout << "Removed: " << std::string{appid} << std::endl; });
82 registry.appInfoUpdated().connect([](const std::shared_ptr<ubuntu::app_launch::Application>& app) {
83 std::cout << "Updated: " << std::string{app->appId()} << std::endl;
84 });
7785
78 std::signal(SIGTERM, [](int signal) -> void { retval.set_value(EXIT_SUCCESS); });86 std::signal(SIGTERM, [](int signal) -> void { retval.set_value(EXIT_SUCCESS); });
79 return retval.get_future().get();87 return retval.get_future().get();

Subscribers

People subscribed via source and target branches