Merge lp:~ted/ubuntu-app-launch/rm-rf-upstart into lp:ubuntu-app-launch

Proposed by Ted Gould
Status: Merged
Approved by: Pete Woods
Approved revision: 309
Merged at revision: 303
Proposed branch: lp:~ted/ubuntu-app-launch/rm-rf-upstart
Merge into: lp:ubuntu-app-launch
Prerequisite: lp:~ted/ubuntu-app-launch/jobs-helpers
Diff against target: 5635 lines (+762/-4229)
47 files modified
CMakeLists.txt (+0/-61)
application-failed.c (+0/-80)
application-job.c (+0/-113)
cgroup-reap-all.c (+0/-65)
debian/control (+2/-7)
debian/ubuntu-app-launch.install (+0/-1)
docs/index.rst (+2/-28)
exec-line-exec-trace.tp (+0/-19)
exec-line-exec.c (+0/-170)
helpers.c (+0/-126)
helpers.h (+0/-12)
libubuntu-app-launch/CMakeLists.txt (+0/-2)
libubuntu-app-launch/helper.cpp (+468/-0)
libubuntu-app-launch/jobs-base.cpp (+4/-15)
libubuntu-app-launch/jobs-upstart.cpp (+0/-1178)
libubuntu-app-launch/jobs-upstart.h (+0/-100)
libubuntu-app-launch/registry-impl.cpp (+0/-1)
libubuntu-app-launch/second-exec-core.c (+0/-2)
libubuntu-app-launch/ubuntu-app-launch.cpp (+0/-1)
tests/CMakeLists.txt (+3/-43)
tests/cgroup-reap-test.cc (+0/-145)
tests/exec-test-archcolon.sh (+0/-18)
tests/exec-test-colon.sh (+0/-18)
tests/exec-test-full.sh (+0/-18)
tests/exec-test-noarch.sh (+0/-18)
tests/exec-test-noinit.sh (+0/-18)
tests/exec-test-nullstr.sh (+0/-18)
tests/exec-test.sh.in (+0/-62)
tests/exec-util-test.cc (+0/-349)
tests/failure-test.cc (+0/-165)
tests/helper-test.cc (+0/-105)
tests/libual-cpp-test.cc (+161/-812)
tests/systemd-mock.h (+5/-0)
tests/zg-mock.h (+117/-0)
untrusted-helper-type-end.c (+0/-66)
upstart-jobs/CMakeLists.txt (+0/-71)
upstart-jobs/application-click.conf.in (+0/-36)
upstart-jobs/application-failed.conf.in (+0/-6)
upstart-jobs/application-legacy.conf.in (+0/-36)
upstart-jobs/application-logrotate.conf (+0/-15)
upstart-jobs/application-snap.conf.in (+0/-37)
upstart-jobs/application.conf.in (+0/-17)
upstart-jobs/test-conffile.sh (+0/-12)
upstart-jobs/untrusted-helper-logrotate.conf (+0/-13)
upstart-jobs/untrusted-helper-type-end.conf.in (+0/-9)
upstart-jobs/untrusted-helper.conf.in (+0/-33)
zg-report-app.c (+0/-108)
To merge this branch: bzr merge lp:~ted/ubuntu-app-launch/rm-rf-upstart
Reviewer Review Type Date Requested Status
Pete Woods (community) Approve
unity-api-1-bot continuous-integration Needs Fixing
Review via email: mp+318039@code.launchpad.net

This proposal supersedes a proposal from 2017-02-14.

Commit message

Remove Upstart

Description of the change

Removes upstart implementations and dependencies. The tests do not work and are fixed in the rm-rf-click branch. They should be landed together.

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
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
306. By Ted Gould

Drop CG Manager variables

307. By Ted Gould

Grab upstream fixes

308. By Ted Gould

Remove Upstart objects from docs

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

Merge updated jobs-helpers

Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Pete Woods (pete-woods) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2017-03-21 03:20:55 +0000
3+++ CMakeLists.txt 2017-03-21 03:20:55 +0000
4@@ -79,9 +79,6 @@
5 pkg_check_modules(CLICK REQUIRED click-0.4>=0.4.18)
6 include_directories(${CLICK_INCLUDE_DIRS})
7
8-pkg_check_modules(LIBUPSTART REQUIRED libupstart)
9-include_directories(${LIBUPSTART_INCLUDE_DIRS})
10-
11 pkg_check_modules(DBUS REQUIRED dbus-1)
12 include_directories(${DBUS_INCLUDE_DIRS})
13
14@@ -130,62 +127,6 @@
15 install(TARGETS desktop-hook RUNTIME DESTINATION "${pkglibexecdir}")
16
17 ####################
18-# exec-line-exec
19-####################
20-
21-add_lttng_gen_tp(NAME exec-line-exec-trace)
22-include_directories(${CMAKE_CURRENT_BINARY_DIR})
23-add_executable(exec-line-exec exec-line-exec.c "${CMAKE_CURRENT_BINARY_DIR}/exec-line-exec-trace.c")
24-set_target_properties(exec-line-exec PROPERTIES OUTPUT_NAME "exec-line-exec")
25-target_link_libraries(exec-line-exec helpers ${LTTNG_LIBRARIES})
26-install(TARGETS exec-line-exec RUNTIME DESTINATION "${pkglibexecdir}")
27-
28-####################
29-# zg-report-app
30-####################
31-
32-add_executable(zg-report-app zg-report-app.c)
33-set_target_properties(zg-report-app PROPERTIES OUTPUT_NAME "zg-report-app")
34-target_link_libraries(zg-report-app ubuntu-launcher ${ZEITGEIST_LIBRARIES} ${GOBJECT2_LIBRARIES} ${GLIB2_LIBRARIES})
35-install(TARGETS zg-report-app RUNTIME DESTINATION "${pkglibexecdir}")
36-
37-####################
38-# application-job
39-####################
40-
41-add_executable(application-job application-job.c)
42-set_target_properties(application-job PROPERTIES OUTPUT_NAME "application-job")
43-target_link_libraries(application-job ubuntu-launcher)
44-install(TARGETS application-job RUNTIME DESTINATION "${pkglibexecdir}")
45-
46-####################
47-# application-failed
48-####################
49-
50-add_executable(application-failed application-failed.c)
51-set_target_properties(application-failed PROPERTIES OUTPUT_NAME "application-failed")
52-target_link_libraries(application-failed ${GIO2_LIBRARIES})
53-install(TARGETS application-failed RUNTIME DESTINATION "${pkglibexecdir}")
54-
55-####################
56-# untrusted-helper-type-end
57-####################
58-
59-add_executable(untrusted-helper-type-end untrusted-helper-type-end.c)
60-set_target_properties(untrusted-helper-type-end PROPERTIES OUTPUT_NAME "untrusted-helper-type-end")
61-target_link_libraries(untrusted-helper-type-end ubuntu-launcher)
62-install(TARGETS untrusted-helper-type-end RUNTIME DESTINATION "${pkglibexecdir}")
63-
64-####################
65-# cgroup-reap-all
66-####################
67-
68-add_executable(cgroup-reap-all cgroup-reap-all.c)
69-set_target_properties(cgroup-reap-all PROPERTIES OUTPUT_NAME "cgroup-reap-all")
70-target_link_libraries(cgroup-reap-all helpers)
71-install(TARGETS cgroup-reap-all RUNTIME DESTINATION "${pkglibexecdir}")
72-
73-####################
74 # oom-adjust-setuid-helper
75 ####################
76
77@@ -200,7 +141,6 @@
78 configure_file("ubuntu-app-launch-desktop.click-hook.in" "${CMAKE_CURRENT_SOURCE_DIR}/debian/ubuntu-app-launch-desktop.click-hook" @ONLY)
79
80 add_subdirectory(libubuntu-app-launch)
81-add_subdirectory(upstart-jobs)
82 add_subdirectory(tools)
83 add_subdirectory(ubuntu-app-test)
84 add_subdirectory(utils)
85@@ -225,7 +165,6 @@
86 TESTS
87 application-icon-finder-test
88 application-info-desktop-test
89- cgroup-reap-test
90 exec-util-test
91 failure-test
92 helper-test
93
94=== removed file 'application-failed.c'
95--- application-failed.c 2016-12-14 21:11:09 +0000
96+++ application-failed.c 1970-01-01 00:00:00 +0000
97@@ -1,80 +0,0 @@
98-
99-/*
100- * Copyright 2013 Canonical Ltd.
101- *
102- * This program is free software: you can redistribute it and/or modify it
103- * under the terms of the GNU General Public License version 3, as published
104- * by the Free Software Foundation.
105- *
106- * This program is distributed in the hope that it will be useful, but
107- * WITHOUT ANY WARRANTY; without even the implied warranties of
108- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
109- * PURPOSE. See the GNU General Public License for more details.
110- *
111- * You should have received a copy of the GNU General Public License along
112- * with this program. If not, see <http://www.gnu.org/licenses/>.
113- *
114- * Authors:
115- * Ted Gould <ted.gould@canonical.com>
116- */
117-
118-#include <gio/gio.h>
119-
120-int
121-main (int argc, char * argv[])
122-{
123- const gchar * job = g_getenv("JOB");
124- g_return_val_if_fail(job != NULL, -1);
125-
126- const gchar * instance = g_getenv("INSTANCE");
127- g_return_val_if_fail(instance != NULL, -1);
128-
129- gboolean crashed = FALSE;
130- if (g_getenv("EXIT_STATUS") != NULL || g_getenv("EXIT_SIGNAL") != NULL) {
131- crashed = TRUE;
132- }
133-
134- gchar * appid = g_strdup(instance);
135- gchar * lasthyphenstanding = NULL;
136- if (g_strcmp0(job, "application-legacy") == 0
137- || g_strcmp0(job, "application-snap") == 0) {
138- lasthyphenstanding = g_strrstr(appid, "-");
139- if (lasthyphenstanding != NULL) {
140- lasthyphenstanding[0] = '\0';
141- } else {
142- g_warning("Legacy job instance '%s' is missing a hyphen", appid);
143- }
144- }
145-
146- if (lasthyphenstanding == NULL) {
147- lasthyphenstanding = "";
148- } else {
149- lasthyphenstanding++;
150- }
151-
152- GDBusConnection * bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
153- g_return_val_if_fail(bus != NULL, -1);
154-
155- GError * error = NULL;
156- g_dbus_connection_emit_signal(bus,
157- NULL, /* destination */
158- "/", /* path */
159- "com.canonical.UbuntuAppLaunch",
160- "ApplicationFailed",
161- g_variant_new("(sss)", appid, lasthyphenstanding, crashed ? "crash" : "start-failure"),
162- &error);
163-
164- g_debug("Emitting failed event '%s' for app '%s'", crashed ? "crash" : "start-failure", appid);
165-
166- if (error != NULL) {
167- g_warning("Unable to emit signal: %s", error->message);
168- g_error_free(error);
169- return -1;
170- }
171-
172- g_dbus_connection_flush_sync(bus, NULL, NULL);
173- g_object_unref(bus);
174- g_free(appid);
175-
176- return 0;
177-}
178
179=== removed file 'application-job.c'
180--- application-job.c 2014-04-30 16:34:06 +0000
181+++ application-job.c 1970-01-01 00:00:00 +0000
182@@ -1,113 +0,0 @@
183-/*
184- * Copyright 2013 Canonical Ltd.
185- *
186- * This program is free software: you can redistribute it and/or modify it
187- * under the terms of the GNU General Public License version 3, as published
188- * by the Free Software Foundation.
189- *
190- * This program is distributed in the hope that it will be useful, but
191- * WITHOUT ANY WARRANTY; without even the implied warranties of
192- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
193- * PURPOSE. See the GNU General Public License for more details.
194- *
195- * You should have received a copy of the GNU General Public License along
196- * with this program. If not, see <http://www.gnu.org/licenses/>.
197- *
198- * Authors:
199- * Ted Gould <ted.gould@canonical.com>
200- */
201-
202-#include <gio/gio.h>
203-#include "libubuntu-app-launch/ubuntu-app-launch.h"
204-
205-int retval = 0;
206-const gchar * global_appid;
207-
208-static void
209-app_started (const gchar * appid, gpointer user_data)
210-{
211- if (g_strcmp0(appid, global_appid) != 0)
212- return;
213- g_debug("Application Started: %s", appid);
214- g_main_loop_quit((GMainLoop *)user_data);
215-}
216-
217-static void
218-app_focus (const gchar * appid, gpointer user_data)
219-{
220- if (g_strcmp0(appid, global_appid) != 0)
221- return;
222- g_debug("Application Focused");
223- g_main_loop_quit((GMainLoop *)user_data);
224-}
225-
226-static void
227-app_failed (const gchar * appid, UbuntuAppLaunchAppFailed failure_type, gpointer user_data)
228-{
229- if (g_strcmp0(appid, global_appid) != 0)
230- return;
231- g_warning("Application Startup Failed");
232- retval = 1;
233- g_main_loop_quit((GMainLoop *)user_data);
234-}
235-
236-/* A fallback so that we can see what is going on. The job can not always signal
237- that it has been started, and thus we wouldn't quit. Which would be a bad thing. */
238-static gboolean
239-timeout_check (gpointer user_data)
240-{
241- g_debug("Timeout reached");
242- g_main_loop_quit((GMainLoop *)user_data);
243- return TRUE; /* Keep the source connected to avoid the disconnect error */
244-}
245-
246-int
247-main (int argc, char * argv[])
248-{
249- GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
250- g_return_val_if_fail(con != NULL, 1);
251-
252- global_appid = g_getenv("APP_ID");
253- g_return_val_if_fail(global_appid != NULL, 1);
254-
255- const gchar * uris_str = g_getenv("APP_URIS");
256- gchar ** uris = NULL;
257- if (uris_str != NULL) {
258- GError * error = NULL;
259- gint uri_count = 0;
260- g_shell_parse_argv(uris_str, &uri_count, &uris, &error);
261-
262- if (error != NULL) {
263- g_warning("Unable to parse uris '%s': %s", uris_str, error->message);
264- g_error_free(error);
265- } else {
266- g_debug("Got %d URIs", uri_count);
267- }
268- }
269-
270- GMainLoop * mainloop = g_main_loop_new(NULL, FALSE);
271-
272- ubuntu_app_launch_observer_add_app_started(app_started, mainloop);
273- ubuntu_app_launch_observer_add_app_focus(app_focus, mainloop);
274- ubuntu_app_launch_observer_add_app_failed(app_failed, mainloop);
275-
276- guint timer = g_timeout_add_seconds(1, timeout_check, mainloop);
277-
278- g_debug("Start Application: %s", global_appid);
279- g_return_val_if_fail(ubuntu_app_launch_start_application(global_appid, (const gchar * const *)uris), -1);
280- g_strfreev(uris);
281-
282- g_debug("Wait for results");
283- g_main_loop_run(mainloop);
284-
285- g_source_remove(timer);
286-
287- ubuntu_app_launch_observer_delete_app_started(app_started, mainloop);
288- ubuntu_app_launch_observer_delete_app_focus(app_focus, mainloop);
289- ubuntu_app_launch_observer_delete_app_failed(app_failed, mainloop);
290-
291- g_main_loop_unref(mainloop);
292- g_object_unref(con);
293-
294- return retval;
295-}
296
297=== removed file 'cgroup-reap-all.c'
298--- cgroup-reap-all.c 2014-11-20 20:33:59 +0000
299+++ cgroup-reap-all.c 1970-01-01 00:00:00 +0000
300@@ -1,65 +0,0 @@
301-/*
302- * Copyright © 2014 Canonical Ltd.
303- *
304- * This program is free software: you can redistribute it and/or modify it
305- * under the terms of the GNU General Public License version 3, as published
306- * by the Free Software Foundation.
307- *
308- * This program is distributed in the hope that it will be useful, but
309- * WITHOUT ANY WARRANTY; without even the implied warranties of
310- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
311- * PURPOSE. See the GNU General Public License for more details.
312- *
313- * You should have received a copy of the GNU General Public License along
314- * with this program. If not, see <http://www.gnu.org/licenses/>.
315- *
316- * Authors:
317- * Ted Gould <ted.gould@canonical.com>
318- */
319-
320-#include "helpers.h"
321-
322-int kill (pid_t pid, int signal);
323-pid_t getpgid (pid_t);
324-
325-int
326-main (int argc, char * argv[])
327-{
328- /* Break off a new process group */
329- setpgid(0, 0);
330-
331- GDBusConnection * cgmanager = cgroup_manager_connection();
332- g_return_val_if_fail(cgmanager != NULL, -1);
333-
334- GPid selfpid = getpid();
335- GPid parentpid = getppid();
336-
337- /* We're gonna try to kill things forever, literally. It's important
338- enough that we can't consider failure an option. */
339- gboolean killed = TRUE;
340- while (killed) {
341- GList * pidlist = pids_from_cgroup(cgmanager, NULL, NULL);
342- GList * head;
343-
344- killed = FALSE;
345-
346- for (head = pidlist; head != NULL; head = g_list_next(head)) {
347- GPid pid = GPOINTER_TO_INT(head->data);
348-
349- /* We don't want to kill ourselves, or if we're being executed by
350- a script, that script, either. We also don't want things in our
351- process group which we forked at the opening */
352- if (pid != selfpid && pid != parentpid && getpgid(pid) != selfpid) {
353- g_debug("Killing pid: %d", pid);
354- kill(pid, SIGKILL);
355- killed = TRUE;
356- }
357- }
358-
359- g_list_free(pidlist);
360- }
361-
362- cgroup_manager_unref(cgmanager);
363-
364- return 0;
365-}
366
367=== modified file 'debian/control'
368--- debian/control 2017-03-07 19:03:36 +0000
369+++ debian/control 2017-03-21 03:20:55 +0000
370@@ -23,18 +23,14 @@
371 liblibertine-dev,
372 liblttng-ust-dev,
373 libmirclient-dev (>= 0.5),
374- libnih-dbus-dev,
375- libnih-dev,
376 libproperties-cpp-dev,
377 # For ABI check to distro version
378 # Make sure to set DEB_BUILD_PROFILES when bootstrapping
379 libubuntu-app-launch3-dev <!stage1>,
380- libupstart-dev,
381 libwhoopsie-dev (>= 0.2.52),
382 libzeitgeist-2.0-dev,
383 gobject-introspection,
384 python3-dbusmock,
385- upstart (>= 1.13),
386 Standards-Version: 3.9.4
387 Homepage: http://launchpad.net/ubuntu-app-launch
388 # If you aren't a member of ~indicator-applet-developers but need to upload packaging changes,
389@@ -46,10 +42,8 @@
390 Architecture: any
391 Depends: ${shlibs:Depends},
392 ${misc:Depends},
393- cgmanager,
394 click-apparmor,
395- libpam-cgfs | libpam-cgm | cgmanager (<< 0.37),
396- upstart (>= 1.13),
397+ dbus-user-session,
398 xmir [amd64 armhf i386],
399 zeitgeist-core,
400 Replaces: upstart-app-launch
401@@ -78,6 +72,7 @@
402 Architecture: any
403 Depends: ${misc:Depends},
404 ${shlibs:Depends},
405+ ubuntu-app-launch (= ${binary:Version}),
406 libertine-tools,
407 Pre-Depends: ${misc:Pre-Depends},
408 Multi-Arch: same
409
410=== modified file 'debian/ubuntu-app-launch.install'
411--- debian/ubuntu-app-launch.install 2016-11-21 20:54:34 +0000
412+++ debian/ubuntu-app-launch.install 2017-03-21 03:20:55 +0000
413@@ -1,3 +1,2 @@
414-usr/share/upstart/sessions/*
415 usr/lib/*/ubuntu-app-launch/*
416 usr/bin/snappy-xmir*
417
418=== modified file 'docs/index.rst'
419--- docs/index.rst 2017-03-21 03:20:55 +0000
420+++ docs/index.rst 2017-03-21 03:20:55 +0000
421@@ -13,10 +13,10 @@
422 managing apps on Ubuntu Touch. It is used by Unity8 and other programs to
423 start and stop applications, as well as query which ones are currently open.
424 It doesn't have its own service or processes though, it relies on the system
425-init daemon to manage the processes (currently Upstart_) but configures them
426+init daemon to manage the processes (currently systemd_) but configures them
427 in a way that they're discoverable and usable by higher level applications.
428
429-.. _Upstart: http://upstart.ubuntu.com/
430+.. _systemd: http://freedesktop.org/wiki/Software/systemd/
431
432
433 Environment Variables
434@@ -25,12 +25,6 @@
435 There are a few environment variables that can effect the behavior of UAL while
436 it is running.
437
438-UBUNTU_APP_LAUNCH_CG_MANAGER_NAME
439- The DBus name that CG Manager registers under if it is on the session bus.
440-
441-UBUNTU_APP_LAUNCH_CG_MANAGER_SESSION_BUS
442- Tell UAL to look on the session bus for CG Manager.
443-
444 UBUNTU_APP_LAUNCH_DEMANGLER
445 Path to the UAL demangler tool that will get the Mir FD for trusted prompt session.
446
447@@ -275,26 +269,6 @@
448 :private-members:
449 :undoc-members:
450
451-Jobs Manager Upstart
452---------------------
453-
454-.. doxygenclass:: ubuntu::app_launch::jobs::manager::Upstart
455- :project: libubuntu-app-launch
456- :members:
457- :protected-members:
458- :private-members:
459- :undoc-members:
460-
461-Jobs Instance Upstart
462----------------------
463-
464-.. doxygenclass:: ubuntu::app_launch::jobs::instance::Upstart
465- :project: libubuntu-app-launch
466- :members:
467- :protected-members:
468- :private-members:
469- :undoc-members:
470-
471 Registry Implementation
472 -----------------------
473
474
475=== removed file 'exec-line-exec-trace.tp'
476--- exec-line-exec-trace.tp 2014-09-17 14:11:59 +0000
477+++ exec-line-exec-trace.tp 1970-01-01 00:00:00 +0000
478@@ -1,19 +0,0 @@
479-
480-TRACEPOINT_EVENT(ubuntu_app_launch, exec_start,
481- TP_ARGS(const char *, appid),
482- TP_FIELDS(
483- ctf_string(appid, appid)
484- )
485-)
486-TRACEPOINT_EVENT(ubuntu_app_launch, exec_parse_complete,
487- TP_ARGS(const char *, appid),
488- TP_FIELDS(
489- ctf_string(appid, appid)
490- )
491-)
492-TRACEPOINT_EVENT(ubuntu_app_launch, exec_pre_exec,
493- TP_ARGS(const char *, appid),
494- TP_FIELDS(
495- ctf_string(appid, appid)
496- )
497-)
498
499=== removed file 'exec-line-exec.c'
500--- exec-line-exec.c 2015-06-30 20:42:24 +0000
501+++ exec-line-exec.c 1970-01-01 00:00:00 +0000
502@@ -1,170 +0,0 @@
503-/*
504- * Copyright 2013 Canonical Ltd.
505- *
506- * This program is free software: you can redistribute it and/or modify it
507- * under the terms of the GNU General Public License version 3, as published
508- * by the Free Software Foundation.
509- *
510- * This program is distributed in the hope that it will be useful, but
511- * WITHOUT ANY WARRANTY; without even the implied warranties of
512- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
513- * PURPOSE. See the GNU General Public License for more details.
514- *
515- * You should have received a copy of the GNU General Public License along
516- * with this program. If not, see <http://www.gnu.org/licenses/>.
517- *
518- * Authors:
519- * Ted Gould <ted.gould@canonical.com>
520- */
521-
522-#include <unistd.h>
523-#include <errno.h>
524-#include <string.h>
525-
526-#include <glib.h>
527-#include <glib/gstdio.h>
528-
529-#include "exec-line-exec-trace.h"
530-#include "helpers.h"
531-#include "ual-tracepoint.h"
532-
533-int
534-main (int argc, char * argv[])
535-{
536- /* Make sure we have work to do */
537- /* This string is quoted using desktop file quoting:
538- http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#exec-variables */
539- const gchar * app_exec = g_getenv("APP_EXEC");
540- if (app_exec == NULL) {
541- /* There should be no reason for this, a g_error() so that it gets
542- picked up by Apport and we can track it */
543- g_error("No exec line given, nothing to do except fail");
544- return 1;
545- }
546-
547- /* For the tracepoints */
548- const gchar * app_id = g_getenv("APP_ID");
549-
550- ual_tracepoint(exec_start, app_id);
551-
552- /* URIs */
553- const gchar * app_uris = g_getenv("APP_URIS");
554-
555- /* Look to see if we have a directory defined that we
556- should be using for everything. If so, change to it
557- and add it to the path */
558- const gchar * appdir = g_getenv("APP_DIR");
559-
560- if (appdir != NULL) {
561- if (g_chdir(appdir) != 0) {
562- g_warning("Unable to change directory to '%s'", appdir);
563- }
564- }
565-
566- /* Protect against app directories that have ':' in them */
567- if (appdir != NULL && strchr(appdir, ':') == NULL) {
568- const gchar * path_path = g_getenv("PATH");
569- if (path_path != NULL && path_path[0] == '\0')
570- path_path = NULL;
571- gchar * path_libpath = NULL;
572- const gchar * path_joinable[4] = { 0 };
573-
574- const gchar * lib_path = g_getenv("LD_LIBRARY_PATH");
575- if (lib_path != NULL && lib_path[0] == '\0')
576- lib_path = NULL;
577- gchar * lib_libpath = g_build_filename(appdir, "lib", NULL);
578- const gchar * lib_joinable[4] = { 0 };
579-
580- const gchar * import_path = g_getenv("QML2_IMPORT_PATH");
581- if (import_path != NULL && import_path[0] == '\0')
582- import_path = NULL;
583- gchar * import_libpath = NULL;
584- const gchar * import_joinable[4] = { 0 };
585-
586- /* If we've got an architecture set insert that into the
587- path before everything else */
588- const gchar * archdir = g_getenv("UBUNTU_APP_LAUNCH_ARCH");
589- if (archdir != NULL && strchr(archdir, ':') == NULL) {
590- path_libpath = g_build_filename(appdir, "lib", archdir, "bin", NULL);
591- import_libpath = g_build_filename(appdir, "lib", archdir, NULL);
592-
593- path_joinable[0] = path_libpath;
594- path_joinable[1] = appdir;
595- path_joinable[2] = path_path;
596-
597- lib_joinable[0] = import_libpath;
598- lib_joinable[1] = lib_libpath;
599- lib_joinable[2] = lib_path;
600-
601- /* Need to check whether the original is NULL because we're
602- appending instead of prepending */
603- if (import_path == NULL) {
604- import_joinable[0] = import_libpath;
605- } else {
606- import_joinable[0] = import_path;
607- import_joinable[1] = import_libpath;
608- }
609- } else {
610- path_joinable[0] = appdir;
611- path_joinable[1] = path_path;
612-
613- lib_joinable[0] = lib_libpath;
614- lib_joinable[1] = lib_path;
615-
616- import_joinable[0] = import_path;
617- }
618-
619- gchar * newpath = g_strjoinv(":", (gchar**)path_joinable);
620- g_setenv("PATH", newpath, TRUE);
621- g_free(path_libpath);
622- g_free(newpath);
623-
624- gchar * newlib = g_strjoinv(":", (gchar**)lib_joinable);
625- g_setenv("LD_LIBRARY_PATH", newlib, TRUE);
626- g_free(lib_libpath);
627- g_free(newlib);
628-
629- if (import_joinable[0] != NULL) {
630- gchar * newimport = g_strjoinv(":", (gchar**)import_joinable);
631- g_setenv("QML2_IMPORT_PATH", newimport, TRUE);
632- g_free(newimport);
633- }
634- g_free(import_libpath);
635- }
636-
637- /* Parse the execiness of it all */
638- GArray * newargv = desktop_exec_parse(app_exec, app_uris);
639- if (newargv == NULL) {
640- g_warning("Unable to parse exec line '%s'", app_exec);
641- return 1;
642- }
643-
644- ual_tracepoint(exec_parse_complete, app_id);
645-
646- if (g_getenv("MIR_SOCKET") != NULL && g_strcmp0(g_getenv("APP_XMIR_ENABLE"), "1") == 0) {
647- g_debug("XMir Helper being used");
648-
649- /* xmir-helper $(APP_ID) $(COMMAND) */
650- const gchar * appid = g_getenv("APP_ID");
651- g_array_prepend_val(newargv, appid);
652-
653- /* Pulling into the heap instead of the code page */
654- char * xmir_helper = g_strdup(XMIR_HELPER);
655- g_array_prepend_val(newargv, xmir_helper);
656- }
657-
658- /* Now exec */
659- gchar ** nargv = (gchar**)g_array_free(newargv, FALSE);
660-
661- ual_tracepoint(exec_pre_exec, app_id);
662-
663- int execret = execvp(nargv[0], nargv);
664-
665- if (execret != 0) {
666- gchar * execprint = g_strjoinv(" ", nargv);
667- g_warning("Unable to exec '%s' in '%s': %s", execprint, appdir, strerror(errno));
668- g_free(execprint);
669- }
670-
671- return execret;
672-}
673
674=== modified file 'helpers.c'
675--- helpers.c 2016-12-14 21:23:09 +0000
676+++ helpers.c 2017-03-21 03:20:55 +0000
677@@ -19,7 +19,6 @@
678
679 #include <json-glib/json-glib.h>
680 #include <click.h>
681-#include <upstart.h>
682 #include "helpers.h"
683
684 /* Take an app ID and validate it and then break it up
685@@ -423,62 +422,6 @@
686 return newargv;
687 }
688
689-/* Set environment various variables to make apps work under
690- * confinement according to:
691- * https://wiki.ubuntu.com/SecurityTeam/Specifications/ApplicationConfinement
692- */
693-void
694-set_confined_envvars (EnvHandle * handle, const gchar * package, const gchar * app_dir)
695-{
696- g_return_if_fail(package != NULL);
697- g_return_if_fail(app_dir != NULL);
698-
699- g_debug("Setting 'UBUNTU_APPLICATION_ISOLATION' to '1'");
700- env_handle_add(handle, "UBUNTU_APPLICATION_ISOLATION", "1");
701-
702- /* Make sure the XDG base dirs are set for the application using
703- * the user's current values/system defaults. We could set these to
704- * what is expected in the AppArmor profile, but that might be too
705- * brittle if someone uses different base dirs.
706- */
707- g_debug("Setting 'XDG_CACHE_HOME' using g_get_user_cache_dir()");
708- env_handle_add(handle, "XDG_CACHE_HOME", g_get_user_cache_dir());
709-
710- g_debug("Setting 'XDG_CONFIG_HOME' using g_get_user_config_dir()");
711- env_handle_add(handle, "XDG_CONFIG_HOME", g_get_user_config_dir());
712-
713- g_debug("Setting 'XDG_DATA_HOME' using g_get_user_data_dir()");
714- env_handle_add(handle, "XDG_DATA_HOME", g_get_user_data_dir());
715-
716- g_debug("Setting 'XDG_RUNTIME_DIR' using g_get_user_runtime_dir()");
717- env_handle_add(handle, "XDG_RUNTIME_DIR", g_get_user_runtime_dir());
718-
719- /* Add the application's dir to the list of sources for data */
720- const gchar * basedatadirs = g_getenv("XDG_DATA_DIRS");
721- if (basedatadirs == NULL || basedatadirs[0] == '\0') {
722- basedatadirs = "/usr/local/share:/usr/share";
723- }
724- gchar * datadirs = g_strjoin(":", app_dir, basedatadirs, NULL);
725- env_handle_add(handle, "XDG_DATA_DIRS", datadirs);
726- g_free(datadirs);
727-
728- /* Set TMPDIR to something sane and application-specific */
729- gchar * tmpdir = g_strdup_printf("%s/confined/%s", g_get_user_runtime_dir(), package);
730- g_debug("Setting 'TMPDIR' to '%s'", tmpdir);
731- env_handle_add(handle, "TMPDIR", tmpdir);
732- g_debug("Creating '%s'", tmpdir);
733- g_mkdir_with_parents(tmpdir, 0700);
734- g_free(tmpdir);
735-
736- /* Do the same for nvidia */
737- gchar * nv_shader_cachedir = g_strdup_printf("%s/%s", g_get_user_cache_dir(), package);
738- g_debug("Setting '__GL_SHADER_DISK_CACHE_PATH' to '%s'", nv_shader_cachedir);
739- env_handle_add(handle, "__GL_SHADER_DISK_CACHE_PATH", nv_shader_cachedir);
740- g_free(nv_shader_cachedir);
741-
742- return;
743-}
744-
745 static void
746 unity_signal_cb (GDBusConnection * con, const gchar * sender, const gchar * path, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
747 {
748@@ -568,72 +511,3 @@
749 g_free(handshake);
750 }
751
752-EnvHandle *
753-env_handle_start (void)
754-{
755- GVariantBuilder * builder = g_variant_builder_new(G_VARIANT_TYPE_ARRAY);
756- return (EnvHandle *)builder;
757-}
758-
759-void
760-env_handle_add (EnvHandle * handle, const gchar * variable, const gchar * value)
761-{
762- g_return_if_fail(handle != NULL);
763- gchar * combinedstr = g_strdup_printf("%s=%s", variable, value);
764- GVariant * env = g_variant_new_take_string(combinedstr);
765- g_variant_builder_add_value((GVariantBuilder*)handle, env);
766-}
767-
768-void
769-env_handle_finish (EnvHandle * handle)
770-{
771- g_return_if_fail(handle != NULL);
772- /* Check to see if we can get the job environment */
773- const gchar * job_name = g_getenv("UPSTART_JOB");
774- const gchar * instance_name = g_getenv("UPSTART_INSTANCE");
775- g_return_if_fail(job_name != NULL);
776-
777- /* Get a bus, let's go! */
778- GDBusConnection * bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
779- g_return_if_fail(bus != NULL);
780-
781- GVariantBuilder builder; /* Target: (assb) */
782- g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
783-
784- /* Setup the job properties */
785- g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY);
786- g_variant_builder_add_value(&builder, g_variant_new_string(job_name));
787- if (instance_name != NULL)
788- g_variant_builder_add_value(&builder, g_variant_new_string(instance_name));
789- g_variant_builder_close(&builder);
790-
791- /* The value itself */
792- g_variant_builder_add_value(&builder, g_variant_builder_end((GVariantBuilder*)handle));
793-
794- /* Do we want to replace? Yes, we do! */
795- g_variant_builder_add_value(&builder, g_variant_new_boolean(TRUE));
796-
797- GError * error = NULL;
798- GVariant * reply = g_dbus_connection_call_sync(bus,
799- DBUS_SERVICE_UPSTART,
800- DBUS_PATH_UPSTART,
801- DBUS_INTERFACE_UPSTART,
802- "SetEnvList",
803- g_variant_builder_end(&builder),
804- NULL, /* reply */
805- G_DBUS_CALL_FLAGS_NONE,
806- -1, /* timeout */
807- NULL, /* cancelable */
808- &error); /* error */
809-
810- if (reply != NULL) {
811- g_variant_unref(reply);
812- }
813-
814- if (error != NULL) {
815- g_warning("Unable to set environment variables: %s", error->message);
816- g_error_free(error);
817- }
818-
819- g_object_unref(bus);
820-}
821
822=== modified file 'helpers.h'
823--- helpers.h 2016-12-14 21:23:09 +0000
824+++ helpers.h 2017-03-21 03:20:55 +0000
825@@ -21,8 +21,6 @@
826
827 G_BEGIN_DECLS
828
829-typedef struct _EnvHandle EnvHandle;
830-
831 gboolean app_id_to_triplet (const gchar * app_id,
832 gchar ** package,
833 gchar ** application,
834@@ -35,16 +33,6 @@
835 const gchar * uri_list);
836 GKeyFile * keyfile_for_appid (const gchar * appid,
837 gchar * * desktopfile);
838-void set_confined_envvars (EnvHandle * handle,
839- const gchar * package,
840- const gchar * app_dir);
841-
842-/* A handle to group environment setting */
843-EnvHandle * env_handle_start (void);
844-void env_handle_add (EnvHandle * handle,
845- const gchar * variable,
846- const gchar * value);
847-void env_handle_finish (EnvHandle * handle);
848
849 typedef struct _handshake_t handshake_t;
850 handshake_t * starting_handshake_start (const gchar * app_id,
851
852=== modified file 'libubuntu-app-launch/CMakeLists.txt'
853--- libubuntu-app-launch/CMakeLists.txt 2017-03-21 03:20:55 +0000
854+++ libubuntu-app-launch/CMakeLists.txt 2017-03-21 03:20:55 +0000
855@@ -74,8 +74,6 @@
856 jobs-base.cpp
857 jobs-systemd.h
858 jobs-systemd.cpp
859-jobs-upstart.h
860-jobs-upstart.cpp
861 )
862
863 set(LAUNCHER_SOURCES
864
865=== added file 'libubuntu-app-launch/helper.cpp'
866--- libubuntu-app-launch/helper.cpp 1970-01-01 00:00:00 +0000
867+++ libubuntu-app-launch/helper.cpp 2017-03-21 03:20:55 +0000
868@@ -0,0 +1,468 @@
869+/*
870+ * Copyright © 2016-2017 Canonical Ltd.
871+ *
872+ * This program is free software: you can redistribute it and/or modify it
873+ * under the terms of the GNU General Public License version 3, as published
874+ * by the Free Software Foundation.
875+ *
876+ * This program is distributed in the hope that it will be useful, but
877+ * WITHOUT ANY WARRANTY; without even the implied warranties of
878+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
879+ * PURPOSE. See the GNU General Public License for more details.
880+ *
881+ * You should have received a copy of the GNU General Public License along
882+ * with this program. If not, see <http://www.gnu.org/licenses/>.
883+ *
884+ * Authors:
885+ * Ted Gould <ted.gould@canonical.com>
886+ */
887+
888+#include <algorithm>
889+#include <list>
890+#include <numeric>
891+
892+#include "helper-impl.h"
893+#include "registry-impl.h"
894+
895+#include "ubuntu-app-launch.h"
896+
897+extern "C" {
898+#include "proxy-socket-demangler.h"
899+#include <gio/gunixfdlist.h>
900+}
901+
902+namespace ubuntu
903+{
904+namespace app_launch
905+{
906+namespace helper_impls
907+{
908+
909+/**********************
910+ * Instance
911+ **********************/
912+
913+BaseInstance::BaseInstance(const std::shared_ptr<jobs::instance::Base>& inst)
914+ : impl{inst}
915+{
916+}
917+
918+BaseInstance::BaseInstance(const std::shared_ptr<Application::Instance>& inst)
919+ : impl{std::dynamic_pointer_cast<jobs::instance::Base>(inst)}
920+{
921+}
922+
923+bool BaseInstance::isRunning()
924+{
925+ return impl->isRunning();
926+}
927+
928+void BaseInstance::stop()
929+{
930+ impl->stop();
931+}
932+
933+/**********************
934+ * Helper Class
935+ **********************/
936+
937+Base::Base(const Helper::Type& type, const AppID& appid, const std::shared_ptr<Registry>& registry)
938+ : _type(type)
939+ , _appid(appid)
940+ , _registry(registry)
941+{
942+}
943+
944+AppID Base::appId()
945+{
946+ return _appid;
947+}
948+
949+bool Base::hasInstances()
950+{
951+ return instances().size() > 0;
952+}
953+
954+std::vector<std::shared_ptr<Helper::Instance>> Base::instances()
955+{
956+ auto insts = _registry->impl->jobs->instances(_appid, _type.value());
957+ std::vector<std::shared_ptr<Helper::Instance>> wrapped;
958+
959+ std::transform(insts.begin(), insts.end(), wrapped.begin(),
960+ [](std::shared_ptr<jobs::instance::Base>& inst) { return std::make_shared<BaseInstance>(inst); });
961+
962+ return wrapped;
963+}
964+
965+/** Find an instance that we already know the ID of */
966+std::shared_ptr<Helper::Instance> Base::existingInstance(const std::string& instanceid)
967+{
968+ auto appinst = _registry->impl->jobs->existing(_appid, _type.value(), instanceid, {});
969+
970+ return std::make_shared<BaseInstance>(appinst);
971+}
972+
973+std::string genInstanceId()
974+{
975+ return std::to_string(g_get_real_time());
976+}
977+
978+std::vector<Application::URL> appURL(const std::vector<Helper::URL>& in)
979+{
980+ std::vector<Application::URL> out;
981+ std::transform(in.begin(), in.end(), out.begin(),
982+ [](Helper::URL url) { return Application::URL::from_raw(url.value()); });
983+ return out;
984+}
985+
986+/** Sets up the executable environment variable based on the appid and
987+ * the type of helper. We look for the exec-tool, but if we can't find
988+ * it we're cool with that and we just execute the helper. If we do find
989+ * an exec-tool we'll use that to fill in the parameters. For legacy appid's
990+ * we'll allow the exec-tool to set everything. */
991+std::list<std::pair<std::string, std::string>> Base::defaultEnv()
992+{
993+ std::list<std::pair<std::string, std::string>> envs{};
994+ auto csnapenv = getenv("SNAP");
995+ std::string helperpath;
996+ if (csnapenv != nullptr)
997+ {
998+ helperpath = std::string{csnapenv} + "/" HELPER_EXEC_TOOL_DIR "/" + _type.value() + "/exec-tool";
999+ }
1000+ else
1001+ {
1002+ helperpath = HELPER_EXEC_TOOL_DIR "/" + _type.value() + "/exec-tool";
1003+ }
1004+
1005+ std::list<std::string> exec;
1006+ /* We have an exec tool that'll give us params */
1007+ if (g_file_test(helperpath.c_str(), G_FILE_TEST_IS_EXECUTABLE))
1008+ {
1009+ const char* chelperenv = getenv("UBUNTU_APP_LAUNCH_HELPER_HELPER");
1010+ if (chelperenv == nullptr)
1011+ {
1012+ chelperenv = HELPER_HELPER_TOOL;
1013+ }
1014+
1015+ if (csnapenv != nullptr)
1016+ {
1017+ exec.push_back(std::string{csnapenv} + "/" + chelperenv);
1018+ }
1019+ else
1020+ {
1021+ exec.push_back(std::string{"/"} + chelperenv);
1022+ }
1023+ exec.push_back(helperpath);
1024+ }
1025+ else
1026+ {
1027+ if (_appid.package.value().empty())
1028+ {
1029+ throw std::runtime_error{
1030+ "Executing a helper that isn't package, but doesn't have an exec-tool. We can't do that. Sorry. Bad "
1031+ "things will happen."};
1032+ }
1033+ }
1034+
1035+ /* This is kinda hard coded for snaps right now, we don't have
1036+ * another posibility today other than really custom stuff. But
1037+ * if we do, we'll need to abstract this. */
1038+ /* Insert package executable */
1039+ if (!_appid.package.value().empty())
1040+ {
1041+ std::string snapdir{"/snap/bin/"};
1042+
1043+ if (_appid.package.value() == _appid.appname.value())
1044+ {
1045+ exec.push_back(snapdir + _appid.package.value());
1046+ }
1047+ else
1048+ {
1049+ exec.push_back(snapdir + _appid.package.value() + "." + _appid.appname.value());
1050+ }
1051+ }
1052+
1053+ exec.push_back("--");
1054+ exec.push_back("%U");
1055+
1056+ envs.emplace_back(
1057+ std::make_pair("APP_EXEC", std::accumulate(exec.begin(), exec.end(), std::string{},
1058+ [](const std::string& accum, const std::string& addon) {
1059+ return accum.empty() ? addon : accum + " " + addon;
1060+ })));
1061+
1062+ return envs;
1063+}
1064+
1065+std::shared_ptr<Helper::Instance> Base::launch(std::vector<Helper::URL> urls)
1066+{
1067+ auto defaultenv = defaultEnv();
1068+ std::function<std::list<std::pair<std::string, std::string>>()> envfunc = [defaultenv]() { return defaultenv; };
1069+
1070+ return std::make_shared<BaseInstance>(_registry->impl->jobs->launch(
1071+ _appid, _type.value(), genInstanceId(), appURL(urls), jobs::manager::launchMode::STANDARD, envfunc));
1072+}
1073+
1074+class MirFDProxy
1075+{
1076+public:
1077+ int mirfd;
1078+ std::shared_ptr<proxySocketDemangler> skel;
1079+ guint handle;
1080+ std::string path;
1081+ std::string name;
1082+
1083+ MirFDProxy(MirPromptSession* session, const AppID& appid, const std::shared_ptr<Registry>& reg)
1084+ : name(g_dbus_connection_get_unique_name(reg->impl->_dbus.get()))
1085+ {
1086+ if (appid.empty())
1087+ {
1088+ throw std::runtime_error{"Invalid AppID"};
1089+ }
1090+
1091+ /* Get the Mir FD */
1092+ std::promise<int> promise;
1093+ mir_prompt_session_new_fds_for_prompt_providers(
1094+ session, 1,
1095+ [](MirPromptSession* session, size_t count, int const* fdin, void* user_data) {
1096+ auto promise = static_cast<std::promise<int>*>(user_data);
1097+
1098+ if (count != 1)
1099+ {
1100+ g_warning("Mir trusted session returned %d FDs instead of one", (int)count);
1101+ promise->set_value(0);
1102+ return;
1103+ }
1104+
1105+ promise->set_value(fdin[0]);
1106+ },
1107+ &promise);
1108+
1109+ mirfd = promise.get_future().get();
1110+
1111+ if (mirfd == 0)
1112+ {
1113+ throw std::runtime_error{"Unable to Mir FD from Prompt Session"};
1114+ }
1115+
1116+ /* Setup the DBus interface */
1117+ std::tie(skel, handle, path) =
1118+ reg->impl->thread.executeOnThread<std::tuple<std::shared_ptr<proxySocketDemangler>, guint, std::string>>(
1119+ [this, appid, reg]() {
1120+ auto skel = std::shared_ptr<proxySocketDemangler>(
1121+ proxy_socket_demangler_skeleton_new(),
1122+ [](proxySocketDemangler* skel) { g_clear_object(&skel); });
1123+ auto handle = g_signal_connect(G_OBJECT(skel.get()), "handle-get-mir-socket",
1124+ G_CALLBACK(staticProxyCb), this);
1125+
1126+ /* Find a path to export on */
1127+ auto dbusAppid = dbusSafe(std::string{appid});
1128+ std::string path;
1129+
1130+ while (path.empty())
1131+ {
1132+ GError* error = nullptr;
1133+ std::string tryname =
1134+ "/com/canonical/UbuntuAppLaunch/" + dbusAppid + "/" + std::to_string(rand());
1135+
1136+ g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(skel.get()), reg->impl->_dbus.get(),
1137+ tryname.c_str(), &error);
1138+
1139+ if (error == nullptr)
1140+ {
1141+ path = tryname;
1142+ }
1143+ else
1144+ {
1145+ if (!g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_OBJECT_PATH_IN_USE))
1146+ {
1147+ std::string message =
1148+ "Unable to export Mir trusted proxy: " + std::string{error->message};
1149+ g_clear_error(&error);
1150+ throw std::runtime_error{message};
1151+ }
1152+ g_clear_error(&error);
1153+ }
1154+ }
1155+
1156+ return std::make_tuple(skel, handle, path);
1157+ });
1158+ }
1159+
1160+ ~MirFDProxy()
1161+ {
1162+ if (mirfd != 0)
1163+ {
1164+ close(mirfd);
1165+ }
1166+
1167+ if (handle != 0)
1168+ {
1169+ g_signal_handler_disconnect(skel.get(), handle);
1170+ }
1171+
1172+ g_dbus_interface_skeleton_unexport(G_DBUS_INTERFACE_SKELETON(skel.get()));
1173+ }
1174+
1175+ static std::string dbusSafe(const std::string& in)
1176+ {
1177+ std::string out = in;
1178+ std::transform(out.begin(), out.end(), out.begin(), [](char in) { return std::isalpha(in) ? in : '_'; });
1179+ return out;
1180+ }
1181+
1182+ bool proxyCb(GDBusMethodInvocation* invocation)
1183+ {
1184+ if (mirfd == 0)
1185+ {
1186+ g_warning("Mir FD proxy called with no FDs!");
1187+ return false;
1188+ }
1189+
1190+ /* Index into fds */
1191+ auto handle = g_variant_new_handle(0);
1192+ auto tuple = g_variant_new_tuple(&handle, 1);
1193+
1194+ GError* error = nullptr;
1195+ GUnixFDList* list = g_unix_fd_list_new();
1196+ g_unix_fd_list_append(list, mirfd, &error);
1197+
1198+ if (error == nullptr)
1199+ {
1200+ g_dbus_method_invocation_return_value_with_unix_fd_list(invocation, tuple, list);
1201+ }
1202+ else
1203+ {
1204+ g_variant_ref_sink(tuple);
1205+ g_variant_unref(tuple);
1206+ }
1207+
1208+ g_object_unref(list);
1209+
1210+ if (error != nullptr)
1211+ {
1212+ g_warning("Unable to pass FD %d: %s", mirfd, error->message);
1213+ g_error_free(error);
1214+ return false;
1215+ }
1216+
1217+ mirfd = 0;
1218+ return true;
1219+ }
1220+
1221+ static gboolean staticProxyCb(GObject* obj, GDBusMethodInvocation* invocation, gpointer user_data)
1222+ {
1223+ return static_cast<MirFDProxy*>(user_data)->proxyCb(invocation) ? TRUE : FALSE;
1224+ }
1225+
1226+ std::string getPath()
1227+ {
1228+ return path;
1229+ }
1230+
1231+ std::string getName()
1232+ {
1233+ return name;
1234+ }
1235+};
1236+
1237+std::shared_ptr<Helper::Instance> Base::launch(MirPromptSession* session, std::vector<Helper::URL> urls)
1238+{
1239+ std::shared_ptr<MirFDProxy> proxy;
1240+ try
1241+ {
1242+ proxy = std::make_shared<MirFDProxy>(session, _appid, _registry);
1243+ }
1244+ catch (std::runtime_error& e)
1245+ {
1246+ g_warning("Error setting up Mir FD Proxy: %s", e.what());
1247+ return {};
1248+ }
1249+
1250+ auto defaultenvs = defaultEnv();
1251+ std::function<std::list<std::pair<std::string, std::string>>()> envfunc = [defaultenvs, proxy]() {
1252+ auto envs = defaultenvs;
1253+
1254+ envs.emplace_back(std::make_pair("UBUNTU_APP_LAUNCH_DEMANGLE_PATH", proxy->getPath()));
1255+ envs.emplace_back(std::make_pair("UBUNTU_APP_LAUNCH_DEMANGLE_NAME", proxy->getName()));
1256+
1257+ return envs;
1258+ };
1259+
1260+ /* This will maintain a reference to the proxy for two
1261+ seconds. And then it'll be dropped. */
1262+ _registry->impl->thread.timeout(std::chrono::seconds{2}, [proxy]() { g_debug("Mir Proxy Timeout"); });
1263+
1264+ return std::make_shared<BaseInstance>(_registry->impl->jobs->launch(
1265+ _appid, _type.value(), genInstanceId(), appURL(urls), jobs::manager::launchMode::STANDARD, envfunc));
1266+}
1267+
1268+} // namespace helper_impl
1269+
1270+/***************************/
1271+/* Helper Public Functions */
1272+/***************************/
1273+
1274+std::shared_ptr<Helper> Helper::create(Type type, AppID appid, std::shared_ptr<Registry> registry)
1275+{
1276+ /* Only one type today */
1277+ return std::make_shared<helper_impls::Base>(type, appid, registry);
1278+}
1279+
1280+/* Hardcore socket stuff */
1281+#include <sys/socket.h>
1282+#include <sys/types.h>
1283+#include <sys/un.h>
1284+
1285+void Helper::setExec(std::vector<std::string> exec)
1286+{
1287+ auto cenv = getenv("UBUNTU_APP_LAUNCH_HELPER_EXECTOOL_SETEXEC_SOCKET");
1288+ if (cenv == nullptr)
1289+ {
1290+ throw std::runtime_error{"Unable to find a socket to write exec information to."};
1291+ }
1292+
1293+ class SmartSocket
1294+ {
1295+ public:
1296+ int fd;
1297+ SmartSocket()
1298+ : fd(socket(AF_UNIX, SOCK_STREAM, 0))
1299+ {
1300+ }
1301+ ~SmartSocket()
1302+ {
1303+ close(fd);
1304+ }
1305+ };
1306+
1307+ SmartSocket sock;
1308+ if (sock.fd <= 0)
1309+ {
1310+ throw std::runtime_error{"Unable to create socket to systemd-helper-helper"};
1311+ }
1312+
1313+ struct sockaddr_un socketaddr = {0};
1314+ socketaddr.sun_family = AF_UNIX;
1315+ strncpy(socketaddr.sun_path, cenv, sizeof(socketaddr.sun_path) - 1);
1316+ socketaddr.sun_path[0] = 0;
1317+
1318+ if (connect(sock.fd, (const struct sockaddr*)&socketaddr, sizeof(struct sockaddr_un)) < 0)
1319+ {
1320+ throw std::runtime_error{"Unable to connecto to socket of systemd-helper-helper"};
1321+ }
1322+
1323+ for (const auto& item : exec)
1324+ {
1325+ auto citem = item.c_str();
1326+ int writesize = write(sock.fd, citem, strlen(citem) + 1);
1327+
1328+ if (writesize <= 0)
1329+ {
1330+ throw std::runtime_error{"Error writing to systemd-helper-helper socket"};
1331+ }
1332+ }
1333+}
1334+
1335+} // namespace app_launch
1336+} // namespace ubuntu
1337
1338=== modified file 'libubuntu-app-launch/jobs-base.cpp'
1339--- libubuntu-app-launch/jobs-base.cpp 2017-03-21 03:20:55 +0000
1340+++ libubuntu-app-launch/jobs-base.cpp 2017-03-21 03:20:55 +0000
1341@@ -26,7 +26,6 @@
1342 #include "helper-impl.h"
1343 #include "jobs-base.h"
1344 #include "jobs-systemd.h"
1345-#include "jobs-upstart.h"
1346 #include "registry-impl.h"
1347
1348 namespace ubuntu
1349@@ -62,22 +61,12 @@
1350 dohandle(handle_appResumed);
1351 }
1352
1353+/** Should determine which jobs backend to use, but we only have
1354+ one right now. */
1355 std::shared_ptr<Base> Base::determineFactory(std::shared_ptr<Registry> registry)
1356 {
1357- /* Checking to see if we have a user bus, that is only started
1358- by systemd so we're in good shape if we have one. We're using
1359- the path instead of the RUNTIME variable because we want to work
1360- around the case of being relocated by the snappy environment */
1361- if (g_file_test(SystemD::userBusPath().c_str(), G_FILE_TEST_EXISTS))
1362- {
1363- g_debug("Building a systemd jobs manager");
1364- return std::make_shared<jobs::manager::SystemD>(registry);
1365- }
1366- else
1367- {
1368- g_debug("Building an Upstart jobs manager");
1369- return std::make_shared<jobs::manager::Upstart>(registry);
1370- }
1371+ g_debug("Building a systemd jobs manager");
1372+ return std::make_shared<jobs::manager::SystemD>(registry);
1373 }
1374
1375 const std::list<std::string>& Base::getAllApplicationJobs() const
1376
1377=== removed file 'libubuntu-app-launch/jobs-upstart.cpp'
1378--- libubuntu-app-launch/jobs-upstart.cpp 2017-03-21 03:20:55 +0000
1379+++ libubuntu-app-launch/jobs-upstart.cpp 1970-01-01 00:00:00 +0000
1380@@ -1,1178 +0,0 @@
1381-/*
1382- * Copyright © 2016 Canonical Ltd.
1383- *
1384- * This program is free software: you can redistribute it and/or modify it
1385- * under the terms of the GNU General Public License version 3, as published
1386- * by the Free Software Foundation.
1387- *
1388- * This program is distributed in the hope that it will be useful, but
1389- * WITHOUT ANY WARRANTY; without even the implied warranties of
1390- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1391- * PURPOSE. See the GNU General Public License for more details.
1392- *
1393- * You should have received a copy of the GNU General Public License along
1394- * with this program. If not, see <http://www.gnu.org/licenses/>.
1395- *
1396- * Authors:
1397- * Ted Gould <ted.gould@canonical.com>
1398- */
1399-
1400-#include <algorithm>
1401-#include <cerrno>
1402-#include <cstring>
1403-#include <map>
1404-#include <numeric>
1405-#include <regex>
1406-
1407-#include <cgmanager/cgmanager.h>
1408-#include <upstart.h>
1409-
1410-#include "application-impl-base.h"
1411-#include "helpers.h"
1412-#include "registry-impl.h"
1413-#include "second-exec-core.h"
1414-
1415-extern "C" {
1416-#include "ubuntu-app-launch-trace.h"
1417-}
1418-
1419-#include "jobs-upstart.h"
1420-
1421-namespace ubuntu
1422-{
1423-namespace app_launch
1424-{
1425-namespace jobs
1426-{
1427-namespace instance
1428-{
1429-
1430-/** An object that represents an instance of a job on Upstart. This
1431- then implements everything needed by the instance interface. Most
1432- applications tie into this today and use it as the backend for
1433- their instances. */
1434-class Upstart : public Base
1435-{
1436-public:
1437- explicit Upstart(const AppID& appId,
1438- const std::string& job,
1439- const std::string& instance,
1440- const std::vector<Application::URL>& urls,
1441- const std::shared_ptr<Registry>& registry);
1442-
1443- /* Query lifecycle */
1444- pid_t primaryPid() override;
1445- std::vector<pid_t> pids() override;
1446-
1447- /* Manage lifecycle */
1448- void stop() override;
1449- void pause() override;
1450- void resume() override;
1451-
1452- /* C Callback */
1453- static void application_start_cb(GObject* obj, GAsyncResult* res, gpointer user_data);
1454-
1455-private:
1456- std::string upstartJobPath();
1457- std::string upstartName();
1458-
1459- static std::vector<pid_t> pids(const std::shared_ptr<Registry>& reg,
1460- const AppID& appid,
1461- const std::string& jobpath);
1462- static std::vector<pid_t> forAllPids(const std::shared_ptr<Registry>& reg,
1463- const AppID& appid,
1464- const std::string& jobpath,
1465- std::function<void(pid_t)> eachPid);
1466-};
1467-
1468-/** Uses Upstart to get the primary PID of the instance using Upstart's
1469- DBus interface */
1470-pid_t Upstart::primaryPid()
1471-{
1472- auto jobpath = upstartJobPath();
1473- if (jobpath.empty())
1474- {
1475- g_debug("Unable to get a valid job path");
1476- return 0;
1477- }
1478-
1479- return registry_->impl->thread.executeOnThread<pid_t>([this, &jobpath]() -> pid_t {
1480- GError* error = nullptr;
1481-
1482- std::string instancename = std::string(appId_);
1483- if (job_ != "application-click")
1484- {
1485- instancename += "-" + instance_;
1486- }
1487-
1488- g_debug("Getting instance by name: %s", instance_.c_str());
1489- auto vinstance_path =
1490- g_dbus_connection_call_sync(registry_->impl->_dbus.get(), /* connection */
1491- DBUS_SERVICE_UPSTART, /* service */
1492- jobpath.c_str(), /* object path */
1493- DBUS_INTERFACE_UPSTART_JOB, /* iface */
1494- "GetInstanceByName", /* method */
1495- g_variant_new("(s)", instancename.c_str()), /* params */
1496- G_VARIANT_TYPE("(o)"), /* return type */
1497- G_DBUS_CALL_FLAGS_NONE, /* flags */
1498- -1, /* timeout: default */
1499- registry_->impl->thread.getCancellable().get(), /* cancellable */
1500- &error);
1501-
1502- if (error != nullptr)
1503- {
1504- g_warning("Unable to get instance '%s' of job '%s': %s", instance_.c_str(), job_.c_str(), error->message);
1505- g_error_free(error);
1506- return 0;
1507- }
1508-
1509- /* Jump rope to make this into a C++ type */
1510- std::string instance_path;
1511- gchar* cinstance_path = nullptr;
1512- g_variant_get(vinstance_path, "(o)", &cinstance_path);
1513- g_variant_unref(vinstance_path);
1514- if (cinstance_path != nullptr)
1515- {
1516- instance_path = cinstance_path;
1517- g_free(cinstance_path);
1518- }
1519-
1520- if (instance_path.empty())
1521- {
1522- g_debug("No instance object for instance name: %s", instance_.c_str());
1523- return 0;
1524- }
1525-
1526- auto props_tuple =
1527- g_dbus_connection_call_sync(registry_->impl->_dbus.get(), /* connection */
1528- DBUS_SERVICE_UPSTART, /* service */
1529- instance_path.c_str(), /* object path */
1530- "org.freedesktop.DBus.Properties", /* interface */
1531- "GetAll", /* method */
1532- g_variant_new("(s)", DBUS_INTERFACE_UPSTART_INSTANCE), /* params */
1533- G_VARIANT_TYPE("(a{sv})"), /* return type */
1534- G_DBUS_CALL_FLAGS_NONE, /* flags */
1535- -1, /* timeout: default */
1536- registry_->impl->thread.getCancellable().get(), /* cancellable */
1537- &error);
1538-
1539- if (error != nullptr)
1540- {
1541- g_warning("Unable to name of properties '%s': %s", instance_path.c_str(), error->message);
1542- g_error_free(error);
1543- error = nullptr;
1544- return 0;
1545- }
1546-
1547- auto props_dict = g_variant_get_child_value(props_tuple, 0);
1548-
1549- pid_t retval = 0;
1550- auto processes = g_variant_lookup_value(props_dict, "processes", G_VARIANT_TYPE("a(si)"));
1551- if (processes != nullptr && g_variant_n_children(processes) > 0)
1552- {
1553-
1554- auto first_entry = g_variant_get_child_value(processes, 0);
1555- auto pidv = g_variant_get_child_value(first_entry, 1);
1556-
1557- retval = g_variant_get_int32(pidv);
1558-
1559- g_variant_unref(pidv);
1560- g_variant_unref(first_entry);
1561- }
1562- else
1563- {
1564- g_debug("Unable to get 'processes' from properties of instance at path: %s", instance_path.c_str());
1565- }
1566-
1567- g_variant_unref(props_dict);
1568-
1569- return retval;
1570- });
1571-}
1572-
1573-/** Generate the full name of the Upstart job for the job, the
1574- instance and how all those fit together.
1575-
1576- Handles the special case of application-click which isn't designed
1577- to have multi-instance apps.
1578-*/
1579-std::string Upstart::upstartName()
1580-{
1581- std::string path = job_ + "-" + std::string(appId_);
1582- if (job_ != "application-click")
1583- {
1584- path += "-";
1585- }
1586- if (!instance_.empty())
1587- {
1588- path += instance_;
1589- }
1590-
1591- return path;
1592-}
1593-
1594-/** Returns all the PIDs that are in the cgroup for this application */
1595-std::vector<pid_t> Upstart::pids()
1596-{
1597- auto manager = std::dynamic_pointer_cast<manager::Upstart>(registry_->impl->jobs);
1598- auto pids = manager->pidsFromCgroup(upstartName());
1599- g_debug("Got %d PIDs for AppID '%s'", int(pids.size()), std::string(appId_).c_str());
1600- return pids;
1601-}
1602-
1603-/** Stops this instance by asking Upstart to stop it. Upstart will then
1604- send a SIGTERM and five seconds later start killing things. */
1605-void Upstart::stop()
1606-{
1607- if (!registry_->impl->thread.executeOnThread<bool>([this]() {
1608- auto manager = std::dynamic_pointer_cast<manager::Upstart>(registry_->impl->jobs);
1609-
1610- g_debug("Stopping job %s app_id %s instance_id %s", job_.c_str(), std::string(appId_).c_str(),
1611- instance_.c_str());
1612-
1613- auto jobpath = upstartJobPath();
1614- if (jobpath.empty())
1615- {
1616- throw new std::runtime_error("Unable to get job path for Upstart job '" + job_ + "'");
1617- }
1618-
1619- GVariantBuilder builder;
1620- g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
1621- g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY);
1622-
1623- g_variant_builder_add_value(
1624- &builder, g_variant_new_take_string(g_strdup_printf("APP_ID=%s", std::string(appId_).c_str())));
1625-
1626- if (!instance_.empty())
1627- {
1628- g_variant_builder_add_value(
1629- &builder, g_variant_new_take_string(g_strdup_printf("INSTANCE_ID=%s", instance_.c_str())));
1630- }
1631-
1632- g_variant_builder_close(&builder);
1633- g_variant_builder_add_value(&builder, g_variant_new_boolean(FALSE)); /* wait */
1634-
1635- GError* error = nullptr;
1636- auto stop_variant =
1637- g_dbus_connection_call_sync(registry_->impl->_dbus.get(), /* Dbus */
1638- DBUS_SERVICE_UPSTART, /* Upstart name */
1639- jobpath.c_str(), /* path */
1640- DBUS_INTERFACE_UPSTART_JOB, /* interface */
1641- "Stop", /* method */
1642- g_variant_builder_end(&builder), /* params */
1643- nullptr, /* return */
1644- G_DBUS_CALL_FLAGS_NONE, /* flags */
1645- -1, /* timeout: default */
1646- registry_->impl->thread.getCancellable().get(), /* cancellable */
1647- &error); /* error (hopefully not) */
1648-
1649- g_clear_pointer(&stop_variant, g_variant_unref);
1650-
1651- if (error != nullptr)
1652- {
1653- g_warning("Unable to stop job %s app_id %s instance_id %s: %s", job_.c_str(),
1654- std::string(appId_).c_str(), instance_.c_str(), error->message);
1655- g_error_free(error);
1656- return false;
1657- }
1658-
1659- return true;
1660- }))
1661- {
1662- g_warning("Unable to stop Upstart instance");
1663- }
1664-}
1665-
1666-/** Create a new Upstart Instance object that can track the job and
1667- get information about it.
1668-
1669- \param appId Application ID
1670- \param job Upstart job name
1671- \param instance Upstart instance name
1672- \param urls URLs sent to the application (only on launch today)
1673- \param registry Registry of persistent connections to use
1674-*/
1675-Upstart::Upstart(const AppID& appId,
1676- const std::string& job,
1677- const std::string& instance,
1678- const std::vector<Application::URL>& urls,
1679- const std::shared_ptr<Registry>& registry)
1680- : Base(appId, job, instance, urls, registry)
1681-{
1682- g_debug("Creating a new Upstart for '%s' instance '%s'", std::string(appId).c_str(), instance.c_str());
1683-}
1684-
1685-/** Small helper that we can new/delete to work better with C stuff */
1686-struct StartCHelper
1687-{
1688- std::shared_ptr<Upstart> ptr;
1689-};
1690-
1691-/** Callback from starting an application. It checks to see whether the
1692- app is already running. If it is already running then we need to send
1693- the URLs to it via DBus.
1694-
1695- \param obj The GDBusConnection object
1696- \param res Async result object
1697- \param user_data A pointer to a StartCHelper structure
1698-*/
1699-void Upstart::application_start_cb(GObject* obj, GAsyncResult* res, gpointer user_data)
1700-{
1701- auto data = static_cast<StartCHelper*>(user_data);
1702- GError* error{nullptr};
1703- GVariant* result{nullptr};
1704-
1705- tracepoint(ubuntu_app_launch, libual_start_message_callback, std::string(data->ptr->appId_).c_str());
1706-
1707- g_debug("Started Message Callback: %s", std::string(data->ptr->appId_).c_str());
1708-
1709- result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(obj), res, &error);
1710-
1711- g_clear_pointer(&result, g_variant_unref);
1712-
1713- if (error != nullptr)
1714- {
1715- if (g_dbus_error_is_remote_error(error))
1716- {
1717- gchar* remote_error = g_dbus_error_get_remote_error(error);
1718- g_debug("Remote error: %s", remote_error);
1719- if (g_strcmp0(remote_error, "com.ubuntu.Upstart0_6.Error.AlreadyStarted") == 0)
1720- {
1721- auto urls = urlsToStrv(data->ptr->urls_);
1722- second_exec(data->ptr->registry_->impl->_dbus.get(), /* DBus */
1723- data->ptr->registry_->impl->thread.getCancellable().get(), /* cancellable */
1724- data->ptr->primaryPid(), /* primary pid */
1725- std::string(data->ptr->appId_).c_str(), /* appid */
1726- std::string(data->ptr->instance_).c_str(), /* instance */
1727- urls.get()); /* urls */
1728- }
1729-
1730- g_free(remote_error);
1731- }
1732- else
1733- {
1734- g_warning("Unable to emit event to start application: %s", error->message);
1735- }
1736- g_error_free(error);
1737- }
1738-
1739- delete data;
1740-}
1741-
1742-std::string Upstart::upstartJobPath()
1743-{
1744- auto manager = std::dynamic_pointer_cast<manager::Upstart>(registry_->impl->jobs);
1745- return manager->upstartJobPath(job_);
1746-}
1747-
1748-/** Go through the list of PIDs calling a function and handling
1749- the issue with getting PIDs being a racey condition.
1750-
1751- \param eachPid Function to run on each PID
1752-*/
1753-std::vector<pid_t> Upstart::forAllPids(const std::shared_ptr<Registry>& reg,
1754- const AppID& appid,
1755- const std::string& jobpath,
1756- std::function<void(pid_t)> eachPid)
1757-{
1758- std::set<pid_t> seenPids;
1759- bool added = true;
1760-
1761- while (added)
1762- {
1763- added = false;
1764- auto pidlist = pids(reg, appid, jobpath);
1765- for (auto pid : pidlist)
1766- {
1767- if (seenPids.insert(pid).second)
1768- {
1769- eachPid(pid);
1770- added = true;
1771- }
1772- }
1773- }
1774-
1775- return std::vector<pid_t>(seenPids.begin(), seenPids.end());
1776-}
1777-
1778-/** Pauses this application by sending SIGSTOP to all the PIDs in the
1779- cgroup and tells Zeitgeist that we've left the application. */
1780-void Upstart::pause()
1781-{
1782- g_debug("Pausing application: %s", std::string(appId_).c_str());
1783-
1784- auto registry = registry_;
1785- auto appid = appId_;
1786- auto instance = instance_;
1787- auto jobpath = upstartJobPath();
1788-
1789- registry->impl->thread.executeOnThread([registry, appid, instance, jobpath] {
1790- auto pids = forAllPids(registry, appid, jobpath, [](pid_t pid) {
1791- auto oomval = oom::paused();
1792- g_debug("Pausing PID: %d (%d)", pid, int(oomval));
1793- signalToPid(pid, SIGSTOP);
1794- oomValueToPid(pid, oomval);
1795- });
1796-
1797- pidListToDbus(registry, appid, instance, pids, "ApplicationPaused");
1798- });
1799-
1800- registry_->impl->zgSendEvent(appId_, ZEITGEIST_ZG_LEAVE_EVENT);
1801-}
1802-
1803-/** Resumes this application by sending SIGCONT to all the PIDs in the
1804- cgroup and tells Zeitgeist that we're accessing the application. */
1805-void Upstart::resume()
1806-{
1807- g_debug("Resuming application: %s", std::string(appId_).c_str());
1808-
1809- auto registry = registry_;
1810- auto appid = appId_;
1811- auto instance = instance_;
1812- auto jobpath = upstartJobPath();
1813-
1814- registry->impl->thread.executeOnThread([registry, appid, instance, jobpath] {
1815- auto pids = forAllPids(registry, appid, jobpath, [](pid_t pid) {
1816- auto oomval = oom::focused();
1817- g_debug("Resuming PID: %d (%d)", pid, int(oomval));
1818- signalToPid(pid, SIGCONT);
1819- oomValueToPid(pid, oomval);
1820- });
1821-
1822- pidListToDbus(registry, appid, instance, pids, "ApplicationResumed");
1823- });
1824-
1825- registry_->impl->zgSendEvent(appId_, ZEITGEIST_ZG_ACCESS_EVENT);
1826-}
1827-
1828-std::vector<pid_t> Upstart::pids(const std::shared_ptr<Registry>& reg, const AppID& appid, const std::string& jobpath)
1829-{
1830- auto manager = std::dynamic_pointer_cast<manager::Upstart>(reg->impl->jobs);
1831- auto pids = manager->pidsFromCgroup(jobpath);
1832- g_debug("Got %d PIDs for AppID '%s'", int(pids.size()), std::string(appid).c_str());
1833- return pids;
1834-}
1835-
1836-} // namespace instances
1837-
1838-namespace manager
1839-{
1840-
1841-Upstart::Upstart(std::shared_ptr<Registry> registry)
1842- : Base(registry)
1843-{
1844-}
1845-
1846-Upstart::~Upstart()
1847-{
1848- auto dohandle = [&](guint& handle) {
1849- if (handle != 0)
1850- {
1851- g_dbus_connection_signal_unsubscribe(dbus_.get(), handle);
1852- handle = 0;
1853- }
1854- };
1855-
1856- dohandle(handle_jobStarted);
1857- dohandle(handle_jobStopped);
1858- dohandle(handle_jobFailed);
1859-}
1860-
1861-/** Launch an application and create a new Upstart instance object to track
1862- its progress.
1863-
1864- \param appId Application ID
1865- \param job Upstart job name
1866- \param instance Upstart instance name
1867- \param urls URLs sent to the application (only on launch today)
1868- \param mode Whether or not to setup the environment for testing
1869- \param getenv A function to get additional environment variable when appropriate
1870-*/
1871-std::shared_ptr<Application::Instance> Upstart::launch(
1872- const AppID& appId,
1873- const std::string& job,
1874- const std::string& instance,
1875- const std::vector<Application::URL>& urls,
1876- launchMode mode,
1877- std::function<std::list<std::pair<std::string, std::string>>(void)>& getenv)
1878-{
1879- if (appId.empty())
1880- return {};
1881-
1882- auto registry = registry_.lock();
1883-
1884- if (!registry)
1885- {
1886- g_warning("Registry object invalid!");
1887- return {};
1888- }
1889-
1890- return registry->impl->thread.executeOnThread<std::shared_ptr<instance::Upstart>>(
1891- [&]() -> std::shared_ptr<instance::Upstart> {
1892- auto manager = std::dynamic_pointer_cast<manager::Upstart>(registry->impl->jobs);
1893- std::string appIdStr{appId};
1894- g_debug("Initializing params for an new instance::Upstart for: %s", appIdStr.c_str());
1895-
1896- tracepoint(ubuntu_app_launch, libual_start, appIdStr.c_str());
1897-
1898- int timeout = 1;
1899- if (ubuntu::app_launch::Registry::Impl::isWatchingAppStarting())
1900- {
1901- timeout = 0;
1902- }
1903-
1904- auto handshake = starting_handshake_start(appIdStr.c_str(), instance.c_str(), timeout);
1905- if (handshake == nullptr)
1906- {
1907- g_warning("Unable to setup starting handshake");
1908- }
1909-
1910- /* Figure out the DBus path for the job */
1911- auto jobpath = manager->upstartJobPath(job);
1912-
1913- /* Build up our environment */
1914- auto env = getenv();
1915-
1916- env.emplace_back(std::make_pair("APP_ID", appIdStr)); /* Application ID */
1917- env.emplace_back(std::make_pair("APP_LAUNCHER_PID", std::to_string(getpid()))); /* Who we are, for bugs */
1918-
1919- if (!urls.empty())
1920- {
1921- auto accumfunc = [](const std::string& prev, Application::URL thisurl) -> std::string {
1922- gchar* gescaped = g_shell_quote(thisurl.value().c_str());
1923- std::string escaped;
1924- if (gescaped != nullptr)
1925- {
1926- escaped = gescaped;
1927- g_free(gescaped);
1928- }
1929- else
1930- {
1931- g_warning("Unable to escape URL: %s", thisurl.value().c_str());
1932- return prev;
1933- }
1934-
1935- if (prev.empty())
1936- {
1937- return escaped;
1938- }
1939- else
1940- {
1941- return prev + " " + escaped;
1942- }
1943- };
1944- auto urlstring = std::accumulate(urls.begin(), urls.end(), std::string{}, accumfunc);
1945- env.emplace_back(std::make_pair("APP_URIS", urlstring));
1946- }
1947-
1948- if (mode == launchMode::TEST)
1949- {
1950- env.emplace_back(std::make_pair("QT_LOAD_TESTABILITY", "1"));
1951- }
1952-
1953- /* Convert to GVariant */
1954- GVariantBuilder builder;
1955- g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
1956-
1957- g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY);
1958-
1959- for (const auto& envvar : env)
1960- {
1961- g_variant_builder_add_value(&builder, g_variant_new_take_string(g_strdup_printf(
1962- "%s=%s", envvar.first.c_str(), envvar.second.c_str())));
1963- }
1964-
1965- g_variant_builder_close(&builder);
1966- g_variant_builder_add_value(&builder, g_variant_new_boolean(TRUE));
1967-
1968- auto retval = std::make_shared<instance::Upstart>(appId, job, instance, urls, registry);
1969- auto chelper = new instance::StartCHelper{};
1970- chelper->ptr = retval;
1971-
1972- tracepoint(ubuntu_app_launch, handshake_wait, appIdStr.c_str());
1973- starting_handshake_wait(handshake);
1974- tracepoint(ubuntu_app_launch, handshake_complete, appIdStr.c_str());
1975-
1976- /* Call the job start function */
1977- g_debug("Asking Upstart to start task for: %s", appIdStr.c_str());
1978- g_dbus_connection_call(registry->impl->_dbus.get(), /* bus */
1979- DBUS_SERVICE_UPSTART, /* service name */
1980- jobpath.c_str(), /* Path */
1981- DBUS_INTERFACE_UPSTART_JOB, /* interface */
1982- "Start", /* method */
1983- g_variant_builder_end(&builder), /* params */
1984- nullptr, /* return */
1985- G_DBUS_CALL_FLAGS_NONE, /* flags */
1986- -1, /* default timeout */
1987- registry->impl->thread.getCancellable().get(), /* cancellable */
1988- instance::Upstart::application_start_cb, /* callback */
1989- chelper /* object */
1990- );
1991-
1992- tracepoint(ubuntu_app_launch, libual_start_message_sent, appIdStr.c_str());
1993-
1994- return retval;
1995- });
1996-}
1997-
1998-/** Special characters that could be an application name that
1999- would activate in a regex */
2000-const static std::regex regexCharacters("([\\.\\-])");
2001-
2002-std::shared_ptr<Application::Instance> Upstart::existing(const AppID& appId,
2003- const std::string& job,
2004- const std::string& instance,
2005- const std::vector<Application::URL>& urls)
2006-{
2007- return std::make_shared<instance::Upstart>(appId, job, instance, urls, registry_.lock());
2008-}
2009-
2010-std::vector<std::shared_ptr<instance::Base>> Upstart::instances(const AppID& appID, const std::string& job)
2011-{
2012- std::vector<std::shared_ptr<instance::Base>> vect;
2013- auto startsWith = std::string(appID);
2014- if (job != "application-click")
2015- {
2016- startsWith += "-";
2017- }
2018-
2019- auto regexstr =
2020- std::string{"^(?:"} + std::regex_replace(startsWith, regexCharacters, "\\$&") + std::string{")(\\d*)$"};
2021- auto instanceRegex = std::regex(regexstr);
2022-
2023- for (auto instance : upstartInstancesForJob(job))
2024- {
2025- std::smatch instanceMatch;
2026- g_debug("Looking at job '%s' instance: %s", job.c_str(), instance.c_str());
2027- if (std::regex_match(instance, instanceMatch, instanceRegex))
2028- {
2029- auto app = existing(appID, job, instanceMatch[1].str(), {});
2030- vect.emplace_back(std::dynamic_pointer_cast<instance::Base>(app));
2031- }
2032- }
2033-
2034- g_debug("App '%s' has %d instances", std::string(appID).c_str(), int(vect.size()));
2035-
2036- return vect;
2037-}
2038-
2039-/** Structure to track the data needed for upstart events. This cleans
2040- up the lifecycle as we're passing this as a pointer through the
2041- GLib calls. */
2042-struct upstartEventData
2043-{
2044- /** Keeping a weak pointer because the handle is held by
2045- the registry implementation. */
2046- std::weak_ptr<Registry> weakReg;
2047-};
2048-
2049-/** Regex to parse the JOB environment variable from Upstart */
2050-const std::regex jobenv_regex{"^JOB=(application\\-(?:click|snap|legacy))$"};
2051-/** Regex to parse the INSTANCE environment variable from Upstart */
2052-const std::regex instanceenv_regex{"^INSTANCE=(.*?)(?:\\-([0-9]*))?+$"};
2053-
2054-/** Core of most of the events that come from Upstart directly. Includes parsing of the
2055- Upstart event environment and calling the appropriate signal with the right Application
2056- object and eventually its instance */
2057-void Upstart::upstartEventEmitted(core::Signal<const std::string&, const std::string&, const std::string&>& signal,
2058- std::shared_ptr<GVariant> params,
2059- const std::shared_ptr<Registry>& reg)
2060-{
2061- std::string jobname;
2062- std::string sappid;
2063- std::string instance;
2064-
2065- gchar* env = nullptr;
2066- auto envs = g_variant_get_child_value(params.get(), 1);
2067- GVariantIter iter;
2068- g_variant_iter_init(&iter, envs);
2069-
2070- while (g_variant_iter_loop(&iter, "s", &env))
2071- {
2072- std::smatch match;
2073- std::string senv = env;
2074-
2075- if (std::regex_match(senv, match, jobenv_regex))
2076- {
2077- jobname = match[1].str();
2078- }
2079- else if (std::regex_match(senv, match, instanceenv_regex))
2080- {
2081- sappid = match[1].str();
2082- instance = match[2].str();
2083- }
2084- }
2085-
2086- g_variant_unref(envs);
2087-
2088- if (jobname.empty())
2089- {
2090- return;
2091- }
2092-
2093- g_debug("Upstart Event for job '%s' appid '%s' instance '%s'", jobname.c_str(), sappid.c_str(), instance.c_str());
2094-
2095- signal(jobname, sappid, instance);
2096-}
2097-
2098-/** Grab the signal object for application startup. If we're not already listing for
2099- those signals this sets up a listener for them. */
2100-core::Signal<const std::string&, const std::string&, const std::string&>& Upstart::jobStarted()
2101-{
2102- std::call_once(flag_jobStarted, [this]() {
2103- auto reg = registry_.lock();
2104-
2105- reg->impl->thread.executeOnThread<bool>([this, reg]() {
2106- upstartEventData* data = new upstartEventData{reg};
2107-
2108- handle_jobStarted = g_dbus_connection_signal_subscribe(
2109- reg->impl->_dbus.get(), /* bus */
2110- nullptr, /* sender */
2111- DBUS_INTERFACE_UPSTART, /* interface */
2112- "EventEmitted", /* signal */
2113- DBUS_PATH_UPSTART, /* path */
2114- "started", /* arg0 */
2115- G_DBUS_SIGNAL_FLAGS_NONE,
2116- [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
2117- gpointer user_data) {
2118- auto data = static_cast<upstartEventData*>(user_data);
2119- auto reg = data->weakReg.lock();
2120-
2121- if (!reg)
2122- {
2123- g_warning("Registry object invalid!");
2124- return;
2125- }
2126-
2127- auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
2128- auto upstart = std::dynamic_pointer_cast<Upstart>(reg->impl->jobs);
2129- upstart->upstartEventEmitted(upstart->sig_jobStarted, sparams, reg);
2130- }, /* callback */
2131- data, /* user data */
2132- [](gpointer user_data) {
2133- auto data = static_cast<upstartEventData*>(user_data);
2134- delete data;
2135- }); /* user data destroy */
2136-
2137- return true;
2138- });
2139- });
2140-
2141- return sig_jobStarted;
2142-}
2143-
2144-/** Grab the signal object for application stopping. If we're not already listing for
2145- those signals this sets up a listener for them. */
2146-core::Signal<const std::string&, const std::string&, const std::string&>& Upstart::jobStopped()
2147-{
2148- std::call_once(flag_jobStopped, [this]() {
2149- auto reg = registry_.lock();
2150-
2151- reg->impl->thread.executeOnThread<bool>([this, reg]() {
2152- upstartEventData* data = new upstartEventData{reg};
2153-
2154- handle_jobStopped = g_dbus_connection_signal_subscribe(
2155- reg->impl->_dbus.get(), /* bus */
2156- nullptr, /* sender */
2157- DBUS_INTERFACE_UPSTART, /* interface */
2158- "EventEmitted", /* signal */
2159- DBUS_PATH_UPSTART, /* path */
2160- "stopped", /* arg0 */
2161- G_DBUS_SIGNAL_FLAGS_NONE,
2162- [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
2163- gpointer user_data) {
2164- auto data = static_cast<upstartEventData*>(user_data);
2165- auto reg = data->weakReg.lock();
2166-
2167- if (!reg)
2168- {
2169- g_warning("Registry object invalid!");
2170- return;
2171- }
2172-
2173- auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
2174- auto upstart = std::dynamic_pointer_cast<Upstart>(reg->impl->jobs);
2175- upstart->upstartEventEmitted(upstart->sig_jobStopped, sparams, reg);
2176- }, /* callback */
2177- data, /* user data */
2178- [](gpointer user_data) {
2179- auto data = static_cast<upstartEventData*>(user_data);
2180- delete data;
2181- }); /* user data destroy */
2182-
2183- return true;
2184- });
2185- });
2186-
2187- return sig_jobStopped;
2188-}
2189-
2190-/** Grab the signal object for application failing. If we're not already listing for
2191- those signals this sets up a listener for them. */
2192-core::Signal<const std::string&, const std::string&, const std::string&, Registry::FailureType>& Upstart::jobFailed()
2193-{
2194- std::call_once(flag_jobFailed, [this]() {
2195- auto reg = registry_.lock();
2196-
2197- reg->impl->thread.executeOnThread<bool>([this, reg]() {
2198- upstartEventData* data = new upstartEventData{reg};
2199-
2200- handle_jobFailed = g_dbus_connection_signal_subscribe(
2201- reg->impl->_dbus.get(), /* bus */
2202- nullptr, /* sender */
2203- "com.canonical.UbuntuAppLaunch", /* interface */
2204- "ApplicationFailed", /* signal */
2205- "/", /* path */
2206- nullptr, /* arg0 */
2207- G_DBUS_SIGNAL_FLAGS_NONE,
2208- [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
2209- gpointer user_data) {
2210- auto data = static_cast<upstartEventData*>(user_data);
2211- auto reg = data->weakReg.lock();
2212-
2213- if (!reg)
2214- {
2215- g_warning("Registry object invalid!");
2216- return;
2217- }
2218-
2219- const gchar* sappid = nullptr;
2220- const gchar* sinstid = nullptr;
2221- const gchar* typestr = nullptr;
2222-
2223- Registry::FailureType type = Registry::FailureType::CRASH;
2224- g_variant_get(params, "(&s&s&s)", &sappid, &sinstid, &typestr);
2225-
2226- if (g_strcmp0("crash", typestr) == 0)
2227- {
2228- type = Registry::FailureType::CRASH;
2229- }
2230- else if (g_strcmp0("start-failure", typestr) == 0)
2231- {
2232- type = Registry::FailureType::START_FAILURE;
2233- }
2234- else
2235- {
2236- g_warning("Application failure type '%s' unknown, reporting as a crash", typestr);
2237- }
2238-
2239- auto upstart = std::dynamic_pointer_cast<Upstart>(reg->impl->jobs);
2240- upstart->sig_jobFailed("application-snap", sappid, sinstid, type);
2241- }, /* callback */
2242- data, /* user data */
2243- [](gpointer user_data) {
2244- auto data = static_cast<upstartEventData*>(user_data);
2245- delete data;
2246- }); /* user data destroy */
2247-
2248- return true;
2249- });
2250- });
2251-
2252- return sig_jobFailed;
2253-}
2254-
2255-/** Initialize the CGManager connection, including a timeout to disconnect
2256- as CGManager doesn't free resources entirely well. So it's better if
2257- we connect and disconnect occationally */
2258-void Upstart::initCGManager()
2259-{
2260- if (cgManager_)
2261- return;
2262-
2263- auto registry = registry_.lock();
2264-
2265- cgManager_ = registry->impl->thread.executeOnThread<std::shared_ptr<GDBusConnection>>([this, registry]() {
2266- bool use_session_bus = g_getenv("UBUNTU_APP_LAUNCH_CG_MANAGER_SESSION_BUS") != nullptr;
2267- if (use_session_bus)
2268- {
2269- /* For working dbusmock */
2270- g_debug("Connecting to CG Manager on session bus");
2271- return registry->impl->_dbus;
2272- }
2273-
2274- auto cancel =
2275- std::shared_ptr<GCancellable>(g_cancellable_new(), [](GCancellable* cancel) { g_clear_object(&cancel); });
2276-
2277- /* Ensure that we do not wait for more than a second */
2278- registry->impl->thread.timeoutSeconds(std::chrono::seconds{1},
2279- [cancel]() { g_cancellable_cancel(cancel.get()); });
2280-
2281- GError* error = nullptr;
2282- auto retval = std::shared_ptr<GDBusConnection>(
2283- g_dbus_connection_new_for_address_sync(CGMANAGER_DBUS_PATH, /* cgmanager path */
2284- G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, /* flags */
2285- nullptr, /* Auth Observer */
2286- cancel.get(), /* Cancellable */
2287- &error),
2288- [](GDBusConnection* con) { g_clear_object(&con); });
2289-
2290- if (error != nullptr)
2291- {
2292- g_warning("Unable to get CGManager connection: %s", error->message);
2293- g_error_free(error);
2294- }
2295-
2296- return retval;
2297- });
2298-
2299- /* NOTE: This will execute on the thread */
2300- registry->impl->thread.timeoutSeconds(std::chrono::seconds{10}, [this]() { cgManager_.reset(); });
2301-}
2302-
2303-/** Get a list of PIDs from a CGroup, uses the CGManager connection to list
2304- all of the PIDs. It is important to note that this is an IPC call, so it can
2305- by its nature, be racy. Once the message has been sent the group can change.
2306- You should take that into account in your usage of it. */
2307-std::vector<pid_t> Upstart::pidsFromCgroup(const std::string& jobpath)
2308-{
2309- initCGManager();
2310- auto lmanager = cgManager_; /* Grab a local copy so we ensure it lasts through our lifetime */
2311- auto registry = registry_.lock();
2312-
2313- return registry->impl->thread.executeOnThread<std::vector<pid_t>>([&jobpath, lmanager]() -> std::vector<pid_t> {
2314- GError* error = nullptr;
2315- const gchar* name = g_getenv("UBUNTU_APP_LAUNCH_CG_MANAGER_NAME");
2316- std::string groupname;
2317- if (!jobpath.empty())
2318- {
2319- groupname = "upstart/" + jobpath;
2320- }
2321-
2322- g_debug("Looking for cg manager '%s' group '%s'", name, groupname.c_str());
2323-
2324- auto vtpids = g_dbus_connection_call_sync(
2325- lmanager.get(), /* connection */
2326- name, /* bus name for direct connection is nullptr */
2327- "/org/linuxcontainers/cgmanager", /* object */
2328- "org.linuxcontainers.cgmanager0_0", /* interface */
2329- "GetTasksRecursive", /* method */
2330- g_variant_new("(ss)", "freezer", groupname.empty() ? "" : groupname.c_str()), /* params */
2331- G_VARIANT_TYPE("(ai)"), /* output */
2332- G_DBUS_CALL_FLAGS_NONE, /* flags */
2333- -1, /* default timeout */
2334- nullptr, /* cancellable */
2335- &error); /* error */
2336-
2337- if (error != nullptr)
2338- {
2339- g_warning("Unable to get PID list from cgroup manager: %s", error->message);
2340- g_error_free(error);
2341- return {};
2342- }
2343-
2344- auto vpids = g_variant_get_child_value(vtpids, 0);
2345- GVariantIter iter;
2346- g_variant_iter_init(&iter, vpids);
2347- gint32 pid;
2348- std::vector<pid_t> pids;
2349-
2350- while (g_variant_iter_loop(&iter, "i", &pid))
2351- {
2352- pids.push_back(pid);
2353- }
2354-
2355- g_variant_unref(vpids);
2356- g_variant_unref(vtpids);
2357-
2358- return pids;
2359- });
2360-}
2361-
2362-/** Looks to find the Upstart object path for a specific Upstart job. This first
2363- checks the cache, and otherwise does the lookup on DBus. */
2364-std::string Upstart::upstartJobPath(const std::string& job)
2365-{
2366- try
2367- {
2368- return upstartJobPathCache_.at(job);
2369- }
2370- catch (std::out_of_range& e)
2371- {
2372- auto registry = registry_.lock();
2373- auto path = registry->impl->thread.executeOnThread<std::string>([this, &job, &registry]() -> std::string {
2374- GError* error = nullptr;
2375- auto job_path_variant =
2376- g_dbus_connection_call_sync(registry->impl->_dbus.get(), /* connection */
2377- DBUS_SERVICE_UPSTART, /* service */
2378- DBUS_PATH_UPSTART, /* path */
2379- DBUS_INTERFACE_UPSTART, /* iface */
2380- "GetJobByName", /* method */
2381- g_variant_new("(s)", job.c_str()), /* params */
2382- G_VARIANT_TYPE("(o)"), /* return */
2383- G_DBUS_CALL_FLAGS_NONE, /* flags */
2384- -1, /* timeout: default */
2385- registry->impl->thread.getCancellable().get(), /* cancellable */
2386- &error); /* error */
2387-
2388- if (error != nullptr)
2389- {
2390- g_warning("Unable to find job '%s': %s", job.c_str(), error->message);
2391- g_error_free(error);
2392- return {};
2393- }
2394-
2395- gchar* job_path = nullptr;
2396- g_variant_get(job_path_variant, "(o)", &job_path);
2397- g_variant_unref(job_path_variant);
2398-
2399- if (job_path != nullptr)
2400- {
2401- std::string path(job_path);
2402- g_free(job_path);
2403- return path;
2404- }
2405- else
2406- {
2407- return {};
2408- }
2409- });
2410-
2411- upstartJobPathCache_[job] = path;
2412- return path;
2413- }
2414-}
2415-
2416-/** Queries Upstart to get all the instances of a given job. This
2417- can take a while as the number of dbus calls is n+1. It is
2418- rare that apps have many instances though. */
2419-std::list<std::string> Upstart::upstartInstancesForJob(const std::string& job)
2420-{
2421- std::string jobpath = upstartJobPath(job);
2422- if (jobpath.empty())
2423- {
2424- return {};
2425- }
2426-
2427- auto registry = registry_.lock();
2428- return registry->impl->thread.executeOnThread<std::list<std::string>>(
2429- [this, &job, &jobpath, &registry]() -> std::list<std::string> {
2430- GError* error = nullptr;
2431- auto instance_tuple =
2432- g_dbus_connection_call_sync(registry->impl->_dbus.get(), /* connection */
2433- DBUS_SERVICE_UPSTART, /* service */
2434- jobpath.c_str(), /* object path */
2435- DBUS_INTERFACE_UPSTART_JOB, /* iface */
2436- "GetAllInstances", /* method */
2437- nullptr, /* params */
2438- G_VARIANT_TYPE("(ao)"), /* return type */
2439- G_DBUS_CALL_FLAGS_NONE, /* flags */
2440- -1, /* timeout: default */
2441- registry->impl->thread.getCancellable().get(), /* cancellable */
2442- &error);
2443-
2444- if (error != nullptr)
2445- {
2446- g_warning("Unable to get instances of job '%s': %s", job.c_str(), error->message);
2447- g_error_free(error);
2448- return {};
2449- }
2450-
2451- if (instance_tuple == nullptr)
2452- {
2453- return {};
2454- }
2455-
2456- auto instance_list = g_variant_get_child_value(instance_tuple, 0);
2457- g_variant_unref(instance_tuple);
2458-
2459- GVariantIter instance_iter;
2460- g_variant_iter_init(&instance_iter, instance_list);
2461- const gchar* instance_path = nullptr;
2462- std::list<std::string> instances;
2463-
2464- while (g_variant_iter_loop(&instance_iter, "&o", &instance_path))
2465- {
2466- auto props_tuple =
2467- g_dbus_connection_call_sync(registry->impl->_dbus.get(), /* connection */
2468- DBUS_SERVICE_UPSTART, /* service */
2469- instance_path, /* object path */
2470- "org.freedesktop.DBus.Properties", /* interface */
2471- "GetAll", /* method */
2472- g_variant_new("(s)", DBUS_INTERFACE_UPSTART_INSTANCE), /* params */
2473- G_VARIANT_TYPE("(a{sv})"), /* return type */
2474- G_DBUS_CALL_FLAGS_NONE, /* flags */
2475- -1, /* timeout: default */
2476- registry->impl->thread.getCancellable().get(), /* cancellable */
2477- &error);
2478-
2479- if (error != nullptr)
2480- {
2481- g_warning("Unable to name of instance '%s': %s", instance_path, error->message);
2482- g_error_free(error);
2483- error = nullptr;
2484- continue;
2485- }
2486-
2487- auto props_dict = g_variant_get_child_value(props_tuple, 0);
2488-
2489- auto namev = g_variant_lookup_value(props_dict, "name", G_VARIANT_TYPE_STRING);
2490- if (namev != nullptr)
2491- {
2492- auto name = g_variant_get_string(namev, nullptr);
2493- g_debug("Adding instance for job '%s': %s", job.c_str(), name);
2494- instances.push_back(name);
2495- g_variant_unref(namev);
2496- }
2497-
2498- g_variant_unref(props_dict);
2499- g_variant_unref(props_tuple);
2500- }
2501-
2502- g_variant_unref(instance_list);
2503-
2504- return instances;
2505- });
2506-}
2507-
2508-std::list<std::string> Upstart::runningAppIds(const std::list<std::string>& jobs)
2509-{
2510- std::list<std::string> instances;
2511-
2512- for (const auto& job : jobs)
2513- {
2514- auto jobinst = upstartInstancesForJob(job);
2515-
2516- if (job != "application-click")
2517- {
2518- /* Remove the instance ID */
2519- std::transform(jobinst.begin(), jobinst.end(), jobinst.begin(),
2520- [](std::string& instancename) -> std::string {
2521- static const std::regex instanceregex("^(.*)-[0-9]*$");
2522- std::smatch match;
2523- if (std::regex_match(instancename, match, instanceregex))
2524- {
2525- return match[1].str();
2526- }
2527- else
2528- {
2529- g_warning("Unable to match instance name: %s", instancename.c_str());
2530- return {};
2531- }
2532- });
2533- }
2534-
2535- instances.splice(instances.begin(), jobinst);
2536- }
2537-
2538- /* Deduplicate Set */
2539- std::set<std::string> instanceset;
2540- for (auto instance : instances)
2541- {
2542- if (!instance.empty())
2543- instanceset.insert(instance);
2544- }
2545-
2546- g_debug("Overall there are %d instances: %s", int(instanceset.size()),
2547- std::accumulate(instanceset.begin(), instanceset.end(), std::string{}, [](const std::string& instr,
2548- std::string instance) {
2549- return instr.empty() ? instance : instr + ", " + instance;
2550- }).c_str());
2551-
2552- return {instanceset.begin(), instanceset.end()};
2553-}
2554-
2555-} // namespace manager
2556-} // namespace jobs
2557-} // namespace app_launch
2558-} // namespace ubuntu
2559
2560=== removed file 'libubuntu-app-launch/jobs-upstart.h'
2561--- libubuntu-app-launch/jobs-upstart.h 2017-03-21 03:20:55 +0000
2562+++ libubuntu-app-launch/jobs-upstart.h 1970-01-01 00:00:00 +0000
2563@@ -1,100 +0,0 @@
2564-/*
2565- * Copyright © 2016 Canonical Ltd.
2566- *
2567- * This program is free software: you can redistribute it and/or modify it
2568- * under the terms of the GNU General Public License version 3, as published
2569- * by the Free Software Foundation.
2570- *
2571- * This program is distributed in the hope that it will be useful, but
2572- * WITHOUT ANY WARRANTY; without even the implied warranties of
2573- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2574- * PURPOSE. See the GNU General Public License for more details.
2575- *
2576- * You should have received a copy of the GNU General Public License along
2577- * with this program. If not, see <http://www.gnu.org/licenses/>.
2578- *
2579- * Authors:
2580- * Ted Gould <ted.gould@canonical.com>
2581- */
2582-
2583-#pragma once
2584-
2585-#include "jobs-base.h"
2586-#include <gio/gio.h>
2587-#include <map>
2588-
2589-namespace ubuntu
2590-{
2591-namespace app_launch
2592-{
2593-namespace jobs
2594-{
2595-namespace manager
2596-{
2597-
2598-class Upstart : public Base
2599-{
2600-public:
2601- Upstart(std::shared_ptr<Registry> registry);
2602- virtual ~Upstart();
2603-
2604- virtual std::shared_ptr<Application::Instance> launch(
2605- const AppID& appId,
2606- const std::string& job,
2607- const std::string& instance,
2608- const std::vector<Application::URL>& urls,
2609- launchMode mode,
2610- std::function<std::list<std::pair<std::string, std::string>>(void)>& getenv) override;
2611- virtual std::shared_ptr<Application::Instance> existing(const AppID& appId,
2612- const std::string& job,
2613- const std::string& instance,
2614- const std::vector<Application::URL>& urls) override;
2615-
2616- virtual std::list<std::string> runningAppIds(const std::list<std::string>& jobs) override;
2617-
2618- virtual std::vector<std::shared_ptr<instance::Base>> instances(const AppID& appID, const std::string& job) override;
2619-
2620- /* Signals to apps */
2621- virtual core::Signal<const std::string&, const std::string&, const std::string&>& jobStarted() override;
2622- virtual core::Signal<const std::string&, const std::string&, const std::string&>& jobStopped() override;
2623- virtual core::Signal<const std::string&, const std::string&, const std::string&, Registry::FailureType>& jobFailed()
2624- override;
2625-
2626- std::vector<pid_t> pidsFromCgroup(const std::string& jobpath);
2627-
2628- std::list<std::string> upstartInstancesForJob(const std::string& job);
2629- std::string upstartJobPath(const std::string& job);
2630-
2631-private:
2632- void initCGManager();
2633-
2634- std::shared_ptr<GDBusConnection> cgManager_;
2635-
2636- /** Getting the Upstart job path is relatively expensive in
2637- that it requires a DBus call. Worth keeping a cache of. */
2638- std::map<std::string, std::string> upstartJobPathCache_;
2639-
2640- core::Signal<const std::string&, const std::string&, const std::string&> sig_jobStarted;
2641- core::Signal<const std::string&, const std::string&, const std::string&> sig_jobStopped;
2642- core::Signal<const std::string&, const std::string&, const std::string&, Registry::FailureType> sig_jobFailed;
2643-
2644- guint handle_jobStarted{0}; /**< GDBus signal watcher handle for app started signal */
2645- guint handle_jobStopped{0}; /**< GDBus signal watcher handle for app stopped signal */
2646- guint handle_jobFailed{0}; /**< GDBus signal watcher handle for app failed signal */
2647-
2648- std::once_flag flag_jobStarted; /**< Variable to track to see if signal handlers are installed for application
2649- started */
2650- std::once_flag flag_jobStopped; /**< Variable to track to see if signal handlers are installed for application
2651- stopped */
2652- std::once_flag
2653- flag_jobFailed; /**< Variable to track to see if signal handlers are installed for application failed */
2654-
2655- void upstartEventEmitted(core::Signal<const std::string&, const std::string&, const std::string&>& signal,
2656- std::shared_ptr<GVariant> params,
2657- const std::shared_ptr<Registry>& reg);
2658-};
2659-
2660-} // namespace manager
2661-} // namespace jobs
2662-} // namespace app_launch
2663-} // namespace ubuntu
2664
2665=== modified file 'libubuntu-app-launch/registry-impl.cpp'
2666--- libubuntu-app-launch/registry-impl.cpp 2017-03-21 03:20:55 +0000
2667+++ libubuntu-app-launch/registry-impl.cpp 2017-03-21 03:20:55 +0000
2668@@ -21,7 +21,6 @@
2669 #include "application-icon-finder.h"
2670 #include "application-impl-base.h"
2671 #include <regex>
2672-#include <upstart.h>
2673
2674 namespace ubuntu
2675 {
2676
2677=== modified file 'libubuntu-app-launch/second-exec-core.c'
2678--- libubuntu-app-launch/second-exec-core.c 2016-12-14 23:03:15 +0000
2679+++ libubuntu-app-launch/second-exec-core.c 2017-03-21 03:20:55 +0000
2680@@ -18,8 +18,6 @@
2681 */
2682
2683 #include <gio/gio.h>
2684-#include <nih/alloc.h>
2685-#include <libnih-dbus.h>
2686 #include "libubuntu-app-launch/ubuntu-app-launch.h"
2687 #include "helpers.h"
2688 #include "second-exec-core.h"
2689
2690=== modified file 'libubuntu-app-launch/ubuntu-app-launch.cpp'
2691--- libubuntu-app-launch/ubuntu-app-launch.cpp 2017-03-21 03:20:55 +0000
2692+++ libubuntu-app-launch/ubuntu-app-launch.cpp 2017-03-21 03:20:55 +0000
2693@@ -19,7 +19,6 @@
2694
2695 extern "C" {
2696 #include "ubuntu-app-launch.h"
2697-#include <upstart.h>
2698 #include <gio/gio.h>
2699 #include <gio/gunixfdlist.h>
2700 #include <string.h>
2701
2702=== modified file 'tests/CMakeLists.txt'
2703--- tests/CMakeLists.txt 2017-02-15 15:10:07 +0000
2704+++ tests/CMakeLists.txt 2017-03-21 03:20:55 +0000
2705@@ -41,13 +41,12 @@
2706 add_executable (libual-test
2707 libual-test.cc
2708 mir-mock.cpp)
2709-target_link_libraries (libual-test gtest_main ${GTEST_MAIN_LIBRARIES} ${LIBUPSTART_LIBRARIES} ${DBUSTEST_LIBRARIES} ubuntu-launcher)
2710+target_link_libraries (libual-test gtest_main ${GTEST_MAIN_LIBRARIES} ${LIBUPSTART_LIBRARIES} ${DBUSTEST_LIBRARIES} launcher-static)
2711
2712 add_executable (libual-cpp-test
2713 libual-cpp-test.cc
2714- ${CMAKE_SOURCE_DIR}/libubuntu-app-launch/glib-thread.cpp
2715 mir-mock.cpp)
2716-target_link_libraries (libual-cpp-test gtest_main ${GTEST_MAIN_LIBRARIES} ${LIBUPSTART_LIBRARIES} ${DBUSTEST_LIBRARIES} ubuntu-launcher)
2717+target_link_libraries (libual-cpp-test gtest_main ${GTEST_MAIN_LIBRARIES} ${LIBUPSTART_LIBRARIES} ${DBUSTEST_LIBRARIES} launcher-static)
2718
2719 add_executable (data-spew
2720 data-spew.c)
2721@@ -123,45 +122,6 @@
2722
2723 file(COPY data DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
2724
2725-# Failure Test
2726-
2727-add_definitions ( -DAPP_FAILED_TOOL="${CMAKE_BINARY_DIR}/application-failed" )
2728-
2729-add_executable (failure-test
2730- failure-test.cc)
2731-target_link_libraries (failure-test gtest_main ${GTEST_MAIN_LIBRARIES} ubuntu-launcher)
2732-add_test (failure-test failure-test)
2733-
2734-# ZG Test
2735-
2736-add_definitions ( -DZG_EVENT_TOOL="${CMAKE_BINARY_DIR}/zg-report-app" )
2737-
2738-add_executable (zg-test
2739- zg-test.cc)
2740-target_link_libraries (zg-test gtest_main ${GTEST_MAIN_LIBRARIES} ${DBUSTEST_LIBRARIES} ${GIO2_LIBRARIES})
2741-add_test (zg-test zg-test)
2742-
2743-# Exec Line Exec Test
2744-
2745-configure_file("exec-test.sh.in" "${CMAKE_CURRENT_BINARY_DIR}/exec-test.sh" @ONLY)
2746-add_test (exec-test "${CMAKE_CURRENT_BINARY_DIR}/exec-test.sh")
2747-
2748-# Exec Utils
2749-
2750-add_executable (exec-util-test
2751- exec-util-test.cc)
2752-target_link_libraries (exec-util-test gtest_main ubuntu-launcher ${GTEST_MAIN_LIBRARIES} ${DBUSTEST_LIBRARIES} ${GIO2_LIBRARIES})
2753-add_test (exec-util-test exec-util-test)
2754-
2755-# CGroup Reap Test
2756-
2757-add_definitions ( -DCG_REAP_TOOL="${CMAKE_BINARY_DIR}/cgroup-reap-all" )
2758-
2759-add_executable (cgroup-reap-test
2760- cgroup-reap-test.cc)
2761-target_link_libraries (cgroup-reap-test gtest_main ${GTEST_MAIN_LIBRARIES} ${DBUSTEST_LIBRARIES} ${GIO2_LIBRARIES})
2762-add_test (cgroup-reap-test cgroup-reap-test)
2763-
2764 # Desktop Hook Test
2765
2766 configure_file ("click-desktop-hook-db/test.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/click-desktop-hook-db/test.conf" @ONLY)
2767@@ -182,7 +142,6 @@
2768
2769 add_custom_target(format-tests
2770 COMMAND clang-format -i -style=file
2771- failure-test.cc
2772 application-info-desktop.cpp
2773 libual-cpp-test.cc
2774 list-apps.cpp
2775@@ -197,4 +156,5 @@
2776 spew-master.h
2777 systemd-mock.h
2778 zg-test.cc
2779+ zg-mock.h
2780 )
2781
2782=== removed file 'tests/cgroup-reap-test.cc'
2783--- tests/cgroup-reap-test.cc 2017-01-11 23:22:52 +0000
2784+++ tests/cgroup-reap-test.cc 1970-01-01 00:00:00 +0000
2785@@ -1,145 +0,0 @@
2786-/*
2787- * Copyright 2014 Canonical Ltd.
2788- *
2789- * This program is free software: you can redistribute it and/or modify it
2790- * under the terms of the GNU General Public License version 3, as published
2791- * by the Free Software Foundation.
2792- *
2793- * This program is distributed in the hope that it will be useful, but
2794- * WITHOUT ANY WARRANTY; without even the implied warranties of
2795- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2796- * PURPOSE. See the GNU General Public License for more details.
2797- *
2798- * You should have received a copy of the GNU General Public License along
2799- * with this program. If not, see <http://www.gnu.org/licenses/>.
2800- *
2801- * Authors:
2802- * Ted Gould <ted.gould@canonical.com>
2803- */
2804-
2805-#include <gtest/gtest.h>
2806-#include <gio/gio.h>
2807-#include <libdbustest/dbus-test.h>
2808-
2809-class CGroupReap : public ::testing::Test
2810-{
2811- protected:
2812- DbusTestService * service = NULL;
2813- DbusTestDbusMock * cgmock = NULL;
2814- GDBusConnection * bus = NULL;
2815- GPid sleeppid = 0;
2816-
2817- virtual void SetUp() {
2818- const gchar * argv[] = { "sleep", "30", NULL };
2819- g_spawn_async(NULL,
2820- (gchar **)argv,
2821- NULL, /* env */
2822- G_SPAWN_SEARCH_PATH,
2823- NULL, NULL, /* child setup */
2824- &sleeppid,
2825- NULL); /* error */
2826- ASSERT_NE(0, sleeppid);
2827-
2828- service = dbus_test_service_new(NULL);
2829-
2830- /* Create the cgroup manager mock */
2831- cgmock = dbus_test_dbus_mock_new("org.test.cgmock");
2832- g_setenv("UBUNTU_APP_LAUNCH_CG_MANAGER_NAME", "org.test.cgmock", TRUE);
2833-
2834- DbusTestDbusMockObject * cgobject = dbus_test_dbus_mock_get_object(cgmock, "/org/linuxcontainers/cgmanager", "org.linuxcontainers.cgmanager0_0", NULL);
2835- /* This Python code executes in dbusmock and checks to see if the sleeping
2836- process is running. If it is, it returns its PID in the list of PIDs, if
2837- not it doesn't return any PIDs. */
2838- gchar * pythoncode = g_strdup_printf(
2839- "if os.spawnlp(os.P_WAIT, 'ps', 'ps', '%d') == 0 :\n"
2840- " ret = [ %d ]\n"
2841- "else:\n"
2842- " ret = [ ]",
2843- sleeppid, sleeppid);
2844- dbus_test_dbus_mock_object_add_method(cgmock, cgobject,
2845- "GetTasksRecursive",
2846- G_VARIANT_TYPE("(ss)"),
2847- G_VARIANT_TYPE("ai"),
2848- pythoncode,
2849- NULL);
2850- g_free(pythoncode);
2851-
2852- /* Put it together */
2853- dbus_test_service_add_task(service, DBUS_TEST_TASK(cgmock));
2854- dbus_test_service_start_tasks(service);
2855-
2856- bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
2857- g_dbus_connection_set_exit_on_close(bus, FALSE);
2858- g_object_add_weak_pointer(G_OBJECT(bus), (gpointer *)&bus);
2859-
2860- /* Make sure we pretend the CG manager is just on our bus */
2861- g_setenv("UBUNTU_APP_LAUNCH_CG_MANAGER_SESSION_BUS", "YES", TRUE);
2862- }
2863-
2864- virtual void TearDown() {
2865- g_clear_object(&cgmock);
2866- g_clear_object(&service);
2867-
2868- g_object_unref(bus);
2869-
2870- unsigned int cleartry = 0;
2871- while (bus != NULL && cleartry < 100) {
2872- pause(100);
2873- cleartry++;
2874- }
2875- ASSERT_EQ(bus, nullptr);
2876-
2877- g_debug("Killing the sleeper: %d", sleeppid);
2878- kill(sleeppid, SIGKILL);
2879- }
2880-
2881- static gboolean pause_helper (gpointer pmainloop) {
2882- g_main_loop_quit(static_cast<GMainLoop *>(pmainloop));
2883- return G_SOURCE_REMOVE;
2884- }
2885-
2886- void pause (guint time) {
2887- if (time > 0) {
2888- GMainLoop * mainloop = g_main_loop_new(NULL, FALSE);
2889- g_timeout_add(time, pause_helper, mainloop);
2890-
2891- g_main_loop_run(mainloop);
2892-
2893- g_main_loop_unref(mainloop);
2894- }
2895-
2896- while (g_main_pending()) {
2897- g_main_iteration(TRUE);
2898- }
2899- }
2900-
2901- bool sleepRunning (void) {
2902- gint status = 1;
2903- gchar * cmdline = g_strdup_printf("ps %d", sleeppid);
2904-
2905- g_spawn_command_line_sync(cmdline, NULL, NULL, &status, NULL);
2906- g_free(cmdline);
2907-
2908- return status == 0;
2909- }
2910-};
2911-
2912-TEST_F(CGroupReap, KillSleep)
2913-{
2914- g_setenv("UPSTART_JOB", "foo", TRUE);
2915- g_setenv("UPSTART_INSTANCE", "bar", TRUE);
2916-
2917- ASSERT_TRUE(g_spawn_command_line_sync(CG_REAP_TOOL, NULL, NULL, NULL, NULL));
2918- EXPECT_FALSE(sleepRunning());
2919-
2920- DbusTestDbusMockObject * cgobject = dbus_test_dbus_mock_get_object(cgmock, "/org/linuxcontainers/cgmanager", "org.linuxcontainers.cgmanager0_0", NULL);
2921- const DbusTestDbusMockCall * calls = NULL;
2922- guint len = 0;
2923-
2924- calls = dbus_test_dbus_mock_object_get_method_calls(cgmock, cgobject, "GetTasksRecursive", &len, NULL);
2925- EXPECT_EQ(2u, len);
2926- EXPECT_STREQ("GetTasksRecursive", calls->name);
2927- EXPECT_TRUE(g_variant_equal(calls->params, g_variant_new("(ss)", "freezer", "")));
2928- ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(cgmock, cgobject, NULL));
2929-}
2930-
2931
2932=== removed file 'tests/exec-test-archcolon.sh'
2933--- tests/exec-test-archcolon.sh 2014-04-30 21:43:28 +0000
2934+++ tests/exec-test-archcolon.sh 1970-01-01 00:00:00 +0000
2935@@ -1,18 +0,0 @@
2936-#!/bin/bash -e
2937-
2938-if [ "$PATH" != "$APP_DIR:/path" ] ; then
2939- echo "Bad PATH: $PATH"
2940- exit 1
2941-fi
2942-
2943-if [ "$LD_LIBRARY_PATH" != "$APP_DIR/lib:/lib" ] ; then
2944- echo "Bad LD_LIBRARY_PATH: $LD_LIBRARY_PATH"
2945- exit 1
2946-fi
2947-
2948-if [ "$QML2_IMPORT_PATH" != "/bar/qml/import" ] ; then
2949- echo "Bad QML import path: $QML2_IMPORT_PATH"
2950- exit 1
2951-fi
2952-
2953-exit 0
2954
2955=== removed file 'tests/exec-test-colon.sh'
2956--- tests/exec-test-colon.sh 2014-04-30 21:43:28 +0000
2957+++ tests/exec-test-colon.sh 1970-01-01 00:00:00 +0000
2958@@ -1,18 +0,0 @@
2959-#!/bin/bash -e
2960-
2961-if [ "$PATH" != "/path" ] ; then
2962- echo "Bad PATH: $PATH"
2963- exit 1
2964-fi
2965-
2966-if [ "$LD_LIBRARY_PATH" != "/lib" ] ; then
2967- echo "Bad LD_LIBRARY_PATH: $LD_LIBRARY_PATH"
2968- exit 1
2969-fi
2970-
2971-if [ "$QML2_IMPORT_PATH" != "/bar/qml/import" ] ; then
2972- echo "Bad QML import path: $QML2_IMPORT_PATH"
2973- exit 1
2974-fi
2975-
2976-exit 0
2977
2978=== removed file 'tests/exec-test-full.sh'
2979--- tests/exec-test-full.sh 2014-04-30 21:43:28 +0000
2980+++ tests/exec-test-full.sh 1970-01-01 00:00:00 +0000
2981@@ -1,18 +0,0 @@
2982-#!/bin/bash -e
2983-
2984-if [ "$PATH" != "$APP_DIR/lib/64bit-amazing/bin:$APP_DIR:/path" ] ; then
2985- echo "Bad PATH: $PATH"
2986- exit 1
2987-fi
2988-
2989-if [ "$LD_LIBRARY_PATH" != "$APP_DIR/lib/64bit-amazing:$APP_DIR/lib:/lib" ] ; then
2990- echo "Bad LD_LIBRARY_PATH: $LD_LIBRARY_PATH"
2991- exit 1
2992-fi
2993-
2994-if [ "$QML2_IMPORT_PATH" != "/bar/qml/import:$APP_DIR/lib/64bit-amazing" ] ; then
2995- echo "Bad QML import path: $QML2_IMPORT_PATH"
2996- exit 1
2997-fi
2998-
2999-exit 0
3000
3001=== removed file 'tests/exec-test-noarch.sh'
3002--- tests/exec-test-noarch.sh 2014-04-30 21:43:28 +0000
3003+++ tests/exec-test-noarch.sh 1970-01-01 00:00:00 +0000
3004@@ -1,18 +0,0 @@
3005-#!/bin/bash -e
3006-
3007-if [ "$PATH" != "$APP_DIR:/path" ] ; then
3008- echo "Bad PATH: $PATH"
3009- exit 1
3010-fi
3011-
3012-if [ "$LD_LIBRARY_PATH" != "$APP_DIR/lib:/lib" ] ; then
3013- echo "Bad LD_LIBRARY_PATH: $LD_LIBRARY_PATH"
3014- exit 1
3015-fi
3016-
3017-if [ "$QML2_IMPORT_PATH" != "/bar/qml/import" ] ; then
3018- echo "Bad QML import path: $QML2_IMPORT_PATH"
3019- exit 1
3020-fi
3021-
3022-exit 0
3023
3024=== removed file 'tests/exec-test-noinit.sh'
3025--- tests/exec-test-noinit.sh 2014-04-30 21:43:28 +0000
3026+++ tests/exec-test-noinit.sh 1970-01-01 00:00:00 +0000
3027@@ -1,18 +0,0 @@
3028-#!/bin/bash -e
3029-
3030-if [ "$PATH" != "$APP_DIR/lib/64bit-amazing/bin:$APP_DIR" ] ; then
3031- echo "Bad PATH: $PATH"
3032- exit 1
3033-fi
3034-
3035-if [ "$LD_LIBRARY_PATH" != "$APP_DIR/lib/64bit-amazing:$APP_DIR/lib" ] ; then
3036- echo "Bad LD_LIBRARY_PATH: $LD_LIBRARY_PATH"
3037- exit 1
3038-fi
3039-
3040-if [ "$QML2_IMPORT_PATH" != "$APP_DIR/lib/64bit-amazing" ] ; then
3041- echo "Bad QML import path: $QML2_IMPORT_PATH"
3042- exit 1
3043-fi
3044-
3045-exit 0
3046
3047=== removed file 'tests/exec-test-nullstr.sh'
3048--- tests/exec-test-nullstr.sh 2014-05-01 15:04:19 +0000
3049+++ tests/exec-test-nullstr.sh 1970-01-01 00:00:00 +0000
3050@@ -1,18 +0,0 @@
3051-#!/bin/bash -e
3052-
3053-if [ "$PATH" != "$APP_DIR/lib/64bit-amazing/bin:$APP_DIR" ] ; then
3054- echo "Bad PATH: $PATH"
3055- exit 1
3056-fi
3057-
3058-if [ "$LD_LIBRARY_PATH" != "$APP_DIR/lib/64bit-amazing:$APP_DIR/lib" ] ; then
3059- echo "Bad LD_LIBRARY_PATH: $LD_LIBRARY_PATH"
3060- exit 1
3061-fi
3062-
3063-if [ "$QML2_IMPORT_PATH" != "$APP_DIR/lib/64bit-amazing" ] ; then
3064- echo "Bad QML import path: $QML2_IMPORT_PATH"
3065- exit 1
3066-fi
3067-
3068-exit 0
3069
3070=== removed file 'tests/exec-test.sh.in'
3071--- tests/exec-test.sh.in 2014-06-05 03:21:12 +0000
3072+++ tests/exec-test.sh.in 1970-01-01 00:00:00 +0000
3073@@ -1,62 +0,0 @@
3074-#!/bin/bash -e
3075-
3076-export PATH=/path
3077-export LD_LIBRARY_PATH=/lib
3078-export APP_EXEC=@CMAKE_CURRENT_SOURCE_DIR@/exec-test-full.sh
3079-export APP_DIR=@CMAKE_CURRENT_BINARY_DIR@
3080-export QML2_IMPORT_PATH=/bar/qml/import
3081-export UBUNTU_APP_LAUNCH_ARCH=64bit-amazing
3082-
3083-echo "Testing Full Test"
3084-@CMAKE_BINARY_DIR@/exec-line-exec
3085-
3086-export PATH=/path
3087-export LD_LIBRARY_PATH=/lib
3088-export APP_EXEC=@CMAKE_CURRENT_SOURCE_DIR@/exec-test-noarch.sh
3089-export APP_DIR=@CMAKE_CURRENT_BINARY_DIR@
3090-export QML2_IMPORT_PATH=/bar/qml/import
3091-unset UBUNTU_APP_LAUNCH_ARCH
3092-
3093-echo "Testing Noarch Test"
3094-@CMAKE_BINARY_DIR@/exec-line-exec
3095-
3096-unset PATH
3097-unset LD_LIBRARY_PATH
3098-export APP_EXEC=@CMAKE_CURRENT_SOURCE_DIR@/exec-test-noinit.sh
3099-export APP_DIR=@CMAKE_CURRENT_BINARY_DIR@
3100-unset QML2_IMPORT_PATH
3101-export UBUNTU_APP_LAUNCH_ARCH=64bit-amazing
3102-
3103-echo "Testing Uninitialized Test"
3104-@CMAKE_BINARY_DIR@/exec-line-exec
3105-
3106-export PATH=/path
3107-export LD_LIBRARY_PATH=/lib
3108-export APP_EXEC=@CMAKE_CURRENT_SOURCE_DIR@/exec-test-colon.sh
3109-export APP_DIR=@CMAKE_CURRENT_BINARY_DIR@/foo:bar
3110-export QML2_IMPORT_PATH=/bar/qml/import
3111-export UBUNTU_APP_LAUNCH_ARCH=64bit-amazing
3112-
3113-echo "Testing Colon Test"
3114-@CMAKE_BINARY_DIR@/exec-line-exec
3115-
3116-export PATH=/path
3117-export LD_LIBRARY_PATH=/lib
3118-export APP_EXEC=@CMAKE_CURRENT_SOURCE_DIR@/exec-test-archcolon.sh
3119-export APP_DIR=@CMAKE_CURRENT_BINARY_DIR@
3120-export QML2_IMPORT_PATH=/bar/qml/import
3121-export UBUNTU_APP_LAUNCH_ARCH=64bit-amazing:amazinger
3122-
3123-echo "Testing Arch Colon Test"
3124-@CMAKE_BINARY_DIR@/exec-line-exec
3125-
3126-export PATH=""
3127-export LD_LIBRARY_PATH=""
3128-export APP_EXEC=@CMAKE_CURRENT_SOURCE_DIR@/exec-test-nullstr.sh
3129-export APP_DIR=@CMAKE_CURRENT_BINARY_DIR@
3130-export QML2_IMPORT_PATH=""
3131-export UBUNTU_APP_LAUNCH_ARCH=64bit-amazing
3132-
3133-echo "Testing Null string Test"
3134-@CMAKE_BINARY_DIR@/exec-line-exec
3135-
3136
3137=== removed file 'tests/exec-util-test.cc'
3138--- tests/exec-util-test.cc 2017-03-06 19:38:17 +0000
3139+++ tests/exec-util-test.cc 1970-01-01 00:00:00 +0000
3140@@ -1,349 +0,0 @@
3141-/*
3142- * Copyright 2013 Canonical Ltd.
3143- *
3144- * This program is free software: you can redistribute it and/or modify it
3145- * under the terms of the GNU General Public License version 3, as published
3146- * by the Free Software Foundation.
3147- *
3148- * This program is distributed in the hope that it will be useful, but
3149- * WITHOUT ANY WARRANTY; without even the implied warranties of
3150- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3151- * PURPOSE. See the GNU General Public License for more details.
3152- *
3153- * You should have received a copy of the GNU General Public License along
3154- * with this program. If not, see <http://www.gnu.org/licenses/>.
3155- *
3156- * Authors:
3157- * Ted Gould <ted.gould@canonical.com>
3158- */
3159-
3160-#include <map>
3161-#include <functional>
3162-
3163-#include <gtest/gtest.h>
3164-#include <libdbustest/dbus-test.h>
3165-#include <gio/gio.h>
3166-#include <libubuntu-app-launch/ubuntu-app-launch.h>
3167-#include <libubuntu-app-launch/registry.h>
3168-
3169-#include "eventually-fixture.h"
3170-#include "libertine-service.h"
3171-
3172-class ExecUtil : public EventuallyFixture
3173-{
3174- protected:
3175- DbusTestService * service = NULL;
3176- DbusTestDbusMock * mock = NULL;
3177- std::shared_ptr<LibertineService> libertine;
3178- GDBusConnection * bus = NULL;
3179- std::string laststarted;
3180-
3181- protected:
3182- static void starting_cb (const gchar * appid, gpointer user_data) {
3183- g_debug("I'm too sexy to callback");
3184- auto pthis = static_cast<ExecUtil*>(user_data);
3185- pthis->laststarted = appid;
3186- }
3187-
3188- virtual void SetUp() {
3189- g_setenv("UPSTART_JOB", "made-up-job", TRUE);
3190- g_setenv("XDG_DATA_DIRS", CMAKE_SOURCE_DIR, TRUE);
3191- g_setenv("XDG_CACHE_HOME", CMAKE_SOURCE_DIR "/libertine-data", TRUE);
3192- g_setenv("XDG_DATA_HOME", CMAKE_SOURCE_DIR "/libertine-home", TRUE);
3193- g_setenv("UBUNTU_APP_LAUNCH_LIBERTINE_LAUNCH", "libertine-launch", TRUE);
3194- g_setenv("UBUNTU_APP_LAUNCH_SNAPD_SOCKET", "/this/should/not/exist", TRUE);
3195- g_setenv("UBUNTU_APP_LAUNCH_SYSTEMD_PATH", "/this/should/not/exist", TRUE);
3196-
3197- service = dbus_test_service_new(NULL);
3198-
3199- mock = dbus_test_dbus_mock_new("com.ubuntu.Upstart");
3200-
3201- DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);
3202-
3203- dbus_test_dbus_mock_object_add_method(mock, obj,
3204- "GetJobByName",
3205- G_VARIANT_TYPE("s"),
3206- G_VARIANT_TYPE("o"),
3207- "ret = dbus.ObjectPath('/com/test/job')",
3208- NULL);
3209-
3210- DbusTestDbusMockObject * jobobj = dbus_test_dbus_mock_get_object(mock, "/com/test/job", "com.ubuntu.Upstart0_6.Job", NULL);
3211-
3212- dbus_test_dbus_mock_object_add_method(mock, jobobj,
3213- "Start",
3214- G_VARIANT_TYPE("(asb)"),
3215- NULL,
3216- "",
3217- NULL);
3218-
3219- dbus_test_service_add_task(service, DBUS_TEST_TASK(mock));
3220-
3221- libertine = std::make_shared<LibertineService>();
3222- dbus_test_service_add_task(service, *libertine);
3223- dbus_test_service_add_task(service, libertine->waitTask());
3224-
3225- dbus_test_service_start_tasks(service);
3226-
3227- bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
3228- g_dbus_connection_set_exit_on_close(bus, FALSE);
3229- g_object_add_weak_pointer(G_OBJECT(bus), (gpointer *)&bus);
3230-
3231- /* Make the handshake clear faster */
3232- ubuntu_app_launch_observer_add_app_starting(starting_cb, this);
3233- }
3234-
3235- virtual void TearDown() {
3236- ubuntu_app_launch_observer_delete_app_starting(starting_cb, this);
3237- ubuntu::app_launch::Registry::clearDefault();
3238-
3239- libertine.reset();
3240- g_clear_object(&mock);
3241- g_clear_object(&service);
3242-
3243- g_object_unref(bus);
3244-
3245- ASSERT_EVENTUALLY_EQ(nullptr, bus);
3246- }
3247-
3248- inline void StartCheckEnv (const std::string& appid, std::map<std::string, std::function<void(const gchar *)>> enums) {
3249- std::map<std::string, bool> env_found;
3250- DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/com/test/job", "com.ubuntu.Upstart0_6.Job", nullptr);
3251-
3252- g_setenv("TEST_CLICK_DB", "click-db-dir", TRUE);
3253- g_setenv("TEST_CLICK_USER", "test-user", TRUE);
3254- g_setenv("UBUNTU_APP_LAUNCH_LINK_FARM", CMAKE_SOURCE_DIR "/link-farm", TRUE);
3255-
3256- laststarted.clear();
3257- ASSERT_TRUE(ubuntu_app_launch_start_application(appid.c_str(), nullptr));
3258- ASSERT_EVENTUALLY_EQ(appid, laststarted);
3259-
3260- guint len = 0;
3261- const DbusTestDbusMockCall * calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, nullptr);
3262-
3263- ASSERT_EQ(1u, len);
3264- ASSERT_NE(nullptr, calls);
3265- ASSERT_STREQ("Start", calls[0].name);
3266-
3267- GVariant * envarray = g_variant_get_child_value(calls[0].params, 0);
3268- GVariantIter iter;
3269- g_variant_iter_init(&iter, envarray);
3270- gchar * envvar = NULL;
3271-
3272- while (g_variant_iter_loop(&iter, "s", &envvar)) {
3273- g_debug("Looking at variable: %s", envvar);
3274- gchar * var = g_strdup(envvar);
3275-
3276- gchar * equal = g_strstr_len(var, -1, "=");
3277- ASSERT_NE(equal, nullptr);
3278-
3279- equal[0] = '\0';
3280- gchar * value = &(equal[1]);
3281-
3282- /* Test the variable */
3283- auto varfunc = enums[var];
3284- EXPECT_NE(nullptr, varfunc);
3285- if (varfunc) {
3286- varfunc(value);
3287- } else {
3288- g_warning("Unable to find function for '%s'", var);
3289- }
3290-
3291- /* Mark it as found */
3292- env_found[var] = true;
3293-
3294- g_free(var);
3295- }
3296-
3297- g_variant_unref(envarray);
3298-
3299- for(auto enumval : enums) {
3300- EXPECT_TRUE(env_found[enumval.first]);
3301- if (!env_found[enumval.first]) {
3302- g_warning("Unable to find enum %s", enumval.first.c_str());
3303- }
3304- }
3305- }
3306-};
3307-
3308-static void
3309-nocheck (const gchar *)
3310-{
3311-}
3312-
3313-TEST_F(ExecUtil, ClickExec)
3314-{
3315-#define APP_DIR CMAKE_SOURCE_DIR "/click-root-dir/.click/users/test-user/com.test.good"
3316-
3317- StartCheckEnv("com.test.good_application_1.2.3", {
3318- {"UBUNTU_APPLICATION_ISOLATION", [](const gchar * value) {
3319- EXPECT_STREQ("1", value); }},
3320- {"XDG_CACHE_HOME", nocheck},
3321- {"XDG_CONFIG_HOME", nocheck},
3322- {"XDG_DATA_HOME", nocheck},
3323- {"XDG_RUNTIME_DIR", nocheck},
3324- {"XDG_DATA_DIRS", [](const gchar * value) {
3325- EXPECT_TRUE(g_str_has_prefix(value, APP_DIR ":")); }},
3326- {"TMPDIR", [](const gchar * value) {
3327- EXPECT_TRUE(g_str_has_suffix(value, "com.test.good")); }},
3328- {"__GL_SHADER_DISK_CACHE_PATH", [](const gchar * value) {
3329- EXPECT_TRUE(g_str_has_suffix(value, "com.test.good")); }},
3330- {"APP_DIR", [](const gchar * value) {
3331- EXPECT_STREQ(APP_DIR, value); }},
3332- {"APP_EXEC", [](const gchar * value) {
3333- EXPECT_STREQ("grep", value); }},
3334- {"APP_ID", [](const gchar * value) {
3335- EXPECT_STREQ("com.test.good_application_1.2.3", value); }},
3336- {"APP_EXEC_POLICY", [](const gchar * value) {
3337- EXPECT_STREQ("com.test.good_application_1.2.3", value); }},
3338- {"APP_LAUNCHER_PID", [](const gchar * value) {
3339- EXPECT_EQ(getpid(), atoi(value)); }},
3340- {"APP_DESKTOP_FILE_PATH", [](const gchar * value) {
3341- EXPECT_STREQ(APP_DIR "/application.desktop", value); }},
3342- {"APP_XMIR_ENABLE", [](const gchar * value) {
3343- EXPECT_STREQ("0", value); }},
3344- {"QML2_IMPORT_PATH", nocheck},
3345- });
3346-
3347-#undef APP_DIR
3348-}
3349-
3350-TEST_F(ExecUtil, DesktopExec)
3351-{
3352- StartCheckEnv("foo", {
3353- {"APP_EXEC", [](const gchar * value) {
3354- EXPECT_STREQ("libertine-launch foo", value); }},
3355- {"APP_DESKTOP_FILE_PATH", [](const gchar * value) {
3356- EXPECT_STREQ(CMAKE_SOURCE_DIR "/applications/foo.desktop", value); }},
3357- {"APP_EXEC_POLICY", [](const gchar * value) {
3358- EXPECT_STREQ("unconfined", value); }},
3359- {"APP_ID", [](const gchar * value) {
3360- EXPECT_STREQ("foo", value); }},
3361- {"INSTANCE_ID", nocheck},
3362- {"APP_LAUNCHER_PID", [](const gchar * value) {
3363- EXPECT_EQ(getpid(), atoi(value)); }},
3364- {"APP_XMIR_ENABLE", [](const gchar * value) {
3365- EXPECT_STREQ("1", value); }},
3366- });
3367-}
3368-
3369-TEST_F(ExecUtil, DesktopMir)
3370-{
3371- StartCheckEnv("xmir", {
3372- {"APP_EXEC", [](const gchar * value) {
3373- EXPECT_STREQ("libertine-launch xfoo", value); }},
3374- {"APP_DESKTOP_FILE_PATH", [](const gchar * value) {
3375- EXPECT_STREQ(CMAKE_SOURCE_DIR "/applications/xmir.desktop", value); }},
3376- {"APP_EXEC_POLICY", [](const gchar * value) {
3377- EXPECT_STREQ("unconfined", value); }},
3378- {"APP_ID", [](const gchar * value) {
3379- EXPECT_STREQ("xmir", value); }},
3380- {"INSTANCE_ID", nocheck},
3381- {"APP_LAUNCHER_PID", [](const gchar * value) {
3382- EXPECT_EQ(getpid(), atoi(value)); }},
3383- {"APP_XMIR_ENABLE", [](const gchar * value) {
3384- EXPECT_STREQ("1", value); }},
3385- });
3386-}
3387-
3388-TEST_F(ExecUtil, DesktopNoMir)
3389-{
3390- StartCheckEnv("noxmir", {
3391- {"APP_EXEC", [](const gchar * value) {
3392- EXPECT_STREQ("noxmir", value); }},
3393- {"APP_DESKTOP_FILE_PATH", [](const gchar * value) {
3394- EXPECT_STREQ(CMAKE_SOURCE_DIR "/applications/noxmir.desktop", value); }},
3395- {"APP_EXEC_POLICY", [](const gchar * value) {
3396- EXPECT_STREQ("unconfined", value); }},
3397- {"APP_ID", [](const gchar * value) {
3398- EXPECT_STREQ("noxmir", value); }},
3399- {"INSTANCE_ID", nocheck},
3400- {"APP_LAUNCHER_PID", [](const gchar * value) {
3401- EXPECT_EQ(getpid(), atoi(value)); }},
3402- {"APP_XMIR_ENABLE", [](const gchar * value) {
3403- EXPECT_STREQ("0", value); }},
3404- });
3405-}
3406-
3407-TEST_F(ExecUtil, ClickMir)
3408-{
3409- StartCheckEnv("com.test.mir_mir_1", {
3410- {"UBUNTU_APPLICATION_ISOLATION", nocheck},
3411- {"XDG_CACHE_HOME", nocheck},
3412- {"XDG_CONFIG_HOME", nocheck},
3413- {"XDG_DATA_HOME", nocheck},
3414- {"XDG_RUNTIME_DIR", nocheck},
3415- {"XDG_DATA_DIRS", nocheck},
3416- {"TMPDIR", nocheck},
3417- {"__GL_SHADER_DISK_CACHE_PATH", nocheck},
3418- {"APP_DIR", nocheck},
3419- {"APP_EXEC", nocheck},
3420- {"APP_ID", [](const gchar * value) {
3421- EXPECT_STREQ("com.test.mir_mir_1", value); }},
3422- {"APP_EXEC_POLICY", [](const gchar * value) {
3423- EXPECT_STREQ("com.test.mir_mir_1", value); }},
3424- {"APP_LAUNCHER_PID", nocheck},
3425- {"APP_DESKTOP_FILE_PATH", nocheck},
3426- {"APP_XMIR_ENABLE", [](const gchar * value) {
3427- EXPECT_STREQ("1", value); }},
3428- {"QML2_IMPORT_PATH", nocheck},
3429- });
3430-}
3431-
3432-TEST_F(ExecUtil, ClickNoMir)
3433-{
3434- StartCheckEnv("com.test.mir_nomir_1", {
3435- {"UBUNTU_APPLICATION_ISOLATION", nocheck},
3436- {"XDG_CACHE_HOME", nocheck},
3437- {"XDG_CONFIG_HOME", nocheck},
3438- {"XDG_DATA_HOME", nocheck},
3439- {"XDG_RUNTIME_DIR", nocheck},
3440- {"XDG_DATA_DIRS", nocheck},
3441- {"TMPDIR", nocheck},
3442- {"__GL_SHADER_DISK_CACHE_PATH", nocheck},
3443- {"APP_DIR", nocheck},
3444- {"APP_EXEC", nocheck},
3445- {"APP_ID", [](const gchar * value) {
3446- EXPECT_STREQ("com.test.mir_nomir_1", value); }},
3447- {"APP_EXEC_POLICY", [](const gchar * value) {
3448- EXPECT_STREQ("com.test.mir_nomir_1", value); }},
3449- {"APP_LAUNCHER_PID", nocheck},
3450- {"APP_DESKTOP_FILE_PATH", nocheck},
3451- {"APP_XMIR_ENABLE", [](const gchar * value) {
3452- EXPECT_STREQ("0", value); }},
3453- {"QML2_IMPORT_PATH", nocheck},
3454- });
3455-}
3456-
3457-TEST_F(ExecUtil, LibertineExec)
3458-{
3459- StartCheckEnv("container-name_test_0.0", {
3460- {"APP_EXEC", [](const gchar * value) {
3461- EXPECT_STREQ("libertine-launch \"--id=container-name\" test", value); }},
3462- {"APP_EXEC_POLICY", [](const gchar * value) {
3463- EXPECT_STREQ("unconfined", value); }},
3464- {"APP_ID", [](const gchar * value) {
3465- EXPECT_STREQ("container-name_test_0.0", value); }},
3466- {"APP_LAUNCHER_PID", [](const gchar * value) {
3467- EXPECT_EQ(getpid(), atoi(value)); }},
3468- {"INSTANCE_ID", nocheck},
3469- {"APP_XMIR_ENABLE", [](const gchar * value) {
3470- EXPECT_STREQ("1", value); }},
3471- });
3472-}
3473-
3474-TEST_F(ExecUtil, LibertineExecUser)
3475-{
3476- StartCheckEnv("container-name_user-app_0.0", {
3477- {"APP_EXEC", [](const gchar * value) {
3478- EXPECT_STREQ("libertine-launch \"--id=container-name\" user-app", value); }},
3479- {"APP_EXEC_POLICY", [](const gchar * value) {
3480- EXPECT_STREQ("unconfined", value); }},
3481- {"APP_ID", [](const gchar * value) {
3482- EXPECT_STREQ("container-name_user-app_0.0", value); }},
3483- {"APP_LAUNCHER_PID", [](const gchar * value) {
3484- EXPECT_EQ(getpid(), atoi(value)); }},
3485- {"INSTANCE_ID", nocheck},
3486- {"APP_XMIR_ENABLE", [](const gchar * value) {
3487- EXPECT_STREQ("1", value); }},
3488- });
3489-}
3490
3491=== removed file 'tests/failure-test.cc'
3492--- tests/failure-test.cc 2017-01-11 23:48:12 +0000
3493+++ tests/failure-test.cc 1970-01-01 00:00:00 +0000
3494@@ -1,165 +0,0 @@
3495-/*
3496- * Copyright 2013 Canonical Ltd.
3497- *
3498- * This program is free software: you can redistribute it and/or modify it
3499- * under the terms of the GNU General Public License version 3, as published
3500- * by the Free Software Foundation.
3501- *
3502- * This program is distributed in the hope that it will be useful, but
3503- * WITHOUT ANY WARRANTY; without even the implied warranties of
3504- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3505- * PURPOSE. See the GNU General Public License for more details.
3506- *
3507- * You should have received a copy of the GNU General Public License along
3508- * with this program. If not, see <http://www.gnu.org/licenses/>.
3509- *
3510- * Authors:
3511- * Ted Gould <ted.gould@canonical.com>
3512- */
3513-
3514-#include "eventually-fixture.h"
3515-#include "registry.h"
3516-#include <gio/gio.h>
3517-#include <glib/gstdio.h>
3518-#include <gtest/gtest.h>
3519-
3520-class FailureTest : public EventuallyFixture
3521-{
3522-private:
3523- GTestDBus* testbus = NULL;
3524-
3525-protected:
3526- std::shared_ptr<ubuntu::app_launch::Registry> registry;
3527-
3528- virtual void SetUp() override
3529- {
3530- /* Click DB test mode */
3531- g_setenv("TEST_CLICK_DB", "click-db-dir", TRUE);
3532- g_setenv("TEST_CLICK_USER", "test-user", TRUE);
3533-
3534- gchar* linkfarmpath = g_build_filename(CMAKE_SOURCE_DIR, "link-farm", NULL);
3535- g_setenv("UBUNTU_APP_LAUNCH_LINK_FARM", linkfarmpath, TRUE);
3536- g_free(linkfarmpath);
3537-
3538- g_setenv("XDG_DATA_DIRS", CMAKE_SOURCE_DIR, TRUE);
3539- g_setenv("XDG_CACHE_HOME", CMAKE_SOURCE_DIR "/libertine-data", TRUE);
3540- g_setenv("XDG_DATA_HOME", CMAKE_SOURCE_DIR "/libertine-home", TRUE);
3541-
3542- g_setenv("UBUNTU_APP_LAUNCH_SYSTEMD_PATH", "/this/should/not/exist", TRUE);
3543-
3544- testbus = g_test_dbus_new(G_TEST_DBUS_NONE);
3545- g_test_dbus_up(testbus);
3546-
3547- registry = std::make_shared<ubuntu::app_launch::Registry>();
3548- }
3549-
3550- virtual void TearDown() override
3551- {
3552- registry.reset();
3553-
3554- g_test_dbus_down(testbus);
3555- g_clear_object(&testbus);
3556- }
3557-};
3558-
3559-TEST_F(FailureTest, CrashTest)
3560-{
3561- g_setenv("EXIT_STATUS", "-100", TRUE);
3562- g_setenv("JOB", "application-click", TRUE);
3563- g_setenv("INSTANCE", "foo", TRUE);
3564-
3565- std::string last_observer;
3566- ubuntu::app_launch::Registry::appFailed(registry).connect(
3567- [&last_observer](std::shared_ptr<ubuntu::app_launch::Application> app,
3568- std::shared_ptr<ubuntu::app_launch::Application::Instance> instance,
3569- ubuntu::app_launch::Registry::FailureType type) {
3570- if (type == ubuntu::app_launch::Registry::FailureType::CRASH)
3571- {
3572- last_observer = app->appId();
3573- }
3574- });
3575-
3576- /* Status based */
3577- ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));
3578-
3579- EXPECT_EVENTUALLY_EQ("foo", last_observer);
3580-
3581- last_observer.clear();
3582- g_unsetenv("EXIT_STATUS");
3583- g_setenv("EXIT_SIGNAL", "KILL", TRUE);
3584-
3585- /* Signal based */
3586- ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));
3587-
3588- EXPECT_EVENTUALLY_EQ("foo", last_observer);
3589-}
3590-
3591-TEST_F(FailureTest, LegacyTest)
3592-{
3593- g_setenv("EXIT_STATUS", "-100", TRUE);
3594- g_setenv("JOB", "application-legacy", TRUE);
3595- g_setenv("INSTANCE", "foo-1234", TRUE);
3596-
3597- std::string last_observer;
3598- ubuntu::app_launch::Registry::appFailed(registry).connect(
3599- [&last_observer](std::shared_ptr<ubuntu::app_launch::Application> app,
3600- std::shared_ptr<ubuntu::app_launch::Application::Instance> instance,
3601- ubuntu::app_launch::Registry::FailureType type) {
3602- g_debug("Signal handler called");
3603- if (type == ubuntu::app_launch::Registry::FailureType::CRASH)
3604- {
3605- last_observer = app->appId();
3606- }
3607- });
3608-
3609- /* Status based */
3610- ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));
3611-
3612- EXPECT_EVENTUALLY_EQ("foo", last_observer);
3613-}
3614-
3615-TEST_F(FailureTest, SnapTest)
3616-{
3617- g_setenv("EXIT_STATUS", "-100", TRUE);
3618- g_setenv("JOB", "application-snap", TRUE);
3619- g_setenv("INSTANCE", "com.test.good_application_1.2.3-1234", TRUE);
3620-
3621- std::string last_observer;
3622- ubuntu::app_launch::Registry::appFailed(registry).connect(
3623- [&last_observer](std::shared_ptr<ubuntu::app_launch::Application> app,
3624- std::shared_ptr<ubuntu::app_launch::Application::Instance> instance,
3625- ubuntu::app_launch::Registry::FailureType type) {
3626- if (type == ubuntu::app_launch::Registry::FailureType::CRASH)
3627- {
3628- last_observer = app->appId();
3629- }
3630- });
3631-
3632- /* Status based */
3633- ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));
3634-
3635- EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", last_observer);
3636-}
3637-
3638-TEST_F(FailureTest, StartTest)
3639-{
3640- g_setenv("JOB", "application-click", TRUE);
3641- g_setenv("INSTANCE", "foo", TRUE);
3642- g_unsetenv("EXIT_STATUS");
3643- g_unsetenv("EXIT_SIGNAL");
3644-
3645- std::string last_observer;
3646- ubuntu::app_launch::Registry::appFailed(registry).connect(
3647- [&last_observer](std::shared_ptr<ubuntu::app_launch::Application> app,
3648- std::shared_ptr<ubuntu::app_launch::Application::Instance> instance,
3649- ubuntu::app_launch::Registry::FailureType type) {
3650- if (type == ubuntu::app_launch::Registry::FailureType::START_FAILURE)
3651- {
3652- last_observer = app->appId();
3653- }
3654- });
3655-
3656- ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));
3657-
3658- EXPECT_EVENTUALLY_EQ("foo", last_observer);
3659-}
3660
3661=== modified file 'tests/helper-test.cc'
3662--- tests/helper-test.cc 2017-01-11 23:22:52 +0000
3663+++ tests/helper-test.cc 2017-03-21 03:20:55 +0000
3664@@ -264,111 +264,6 @@
3665 return;
3666 }
3667
3668-TEST_F(HelperTest, SetConfinedEnvvars)
3669-{
3670- g_unsetenv("XDG_DATA_DIRS");
3671-
3672- DbusTestService * service = dbus_test_service_new(NULL);
3673- DbusTestDbusMock * mock = dbus_test_dbus_mock_new("com.ubuntu.Upstart");
3674-
3675- DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);
3676-
3677- dbus_test_dbus_mock_object_add_method(mock, obj,
3678- "SetEnvList",
3679- G_VARIANT_TYPE("(asasb)"),
3680- NULL,
3681- "",
3682- NULL);
3683-
3684- dbus_test_service_add_task(service, DBUS_TEST_TASK(mock));
3685- dbus_test_service_start_tasks(service);
3686-
3687- GDBusConnection * bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
3688- g_dbus_connection_set_exit_on_close(bus, FALSE);
3689- g_object_add_weak_pointer(G_OBJECT(bus), (gpointer *)&bus);
3690-
3691- /* Not a test other than "don't crash" */
3692- EnvHandle * handle = env_handle_start();
3693- set_confined_envvars(handle, "foo-app-pkg", "/foo/bar");
3694- env_handle_finish(handle);
3695-
3696- guint len = 0;
3697- const DbusTestDbusMockCall * calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "SetEnvList", &len, NULL);
3698-
3699- ASSERT_EQ(guint(1), len);
3700- ASSERT_NE(calls, nullptr);
3701- ASSERT_STREQ("SetEnvList", calls[0].name);
3702-
3703- bool got_app_isolation = false;
3704- bool got_cache_home = false;
3705- bool got_config_home = false;
3706- bool got_data_home = false;
3707- bool got_runtime_dir = false;
3708- bool got_data_dirs = false;
3709- bool got_temp_dir = false;
3710- bool got_shader_dir = false;
3711-
3712- GVariant * envarray = g_variant_get_child_value(calls[0].params, 1);
3713- GVariantIter iter;
3714- g_variant_iter_init(&iter, envarray);
3715- gchar * envvar = NULL;
3716-
3717- while (g_variant_iter_loop(&iter, "s", &envvar)) {
3718- gchar * var = g_strdup(envvar);
3719-
3720- gchar * equal = g_strstr_len(var, -1, "=");
3721- ASSERT_NE(equal, nullptr);
3722-
3723- equal[0] = '\0';
3724- gchar * value = &(equal[1]);
3725-
3726- if (g_strcmp0(var, "UBUNTU_APPLICATION_ISOLATION") == 0) {
3727- ASSERT_STREQ(value, "1");
3728- got_app_isolation = true;
3729- } else if (g_strcmp0(var, "XDG_CACHE_HOME") == 0) {
3730- got_cache_home = true;
3731- } else if (g_strcmp0(var, "XDG_CONFIG_HOME") == 0) {
3732- got_config_home = true;
3733- } else if (g_strcmp0(var, "XDG_DATA_HOME") == 0) {
3734- got_data_home = true;
3735- } else if (g_strcmp0(var, "XDG_RUNTIME_DIR") == 0) {
3736- got_runtime_dir = true;
3737- } else if (g_strcmp0(var, "XDG_DATA_DIRS") == 0) {
3738- ASSERT_TRUE(g_str_has_prefix(value, "/foo/bar:"));
3739- ASSERT_TRUE(g_strstr_len(value, -1, "/usr/share") != NULL);
3740- got_data_dirs = true;
3741- } else if (g_strcmp0(var, "TMPDIR") == 0) {
3742- ASSERT_TRUE(g_str_has_suffix(value, "foo-app-pkg"));
3743- got_temp_dir = true;
3744- } else if (g_strcmp0(var, "__GL_SHADER_DISK_CACHE_PATH") == 0) {
3745- ASSERT_TRUE(g_str_has_suffix(value, "foo-app-pkg"));
3746- got_shader_dir = true;
3747- } else {
3748- g_warning("Unknown variable! %s", var);
3749- ASSERT_TRUE(false);
3750- }
3751-
3752- g_free(var);
3753- }
3754-
3755- g_variant_unref(envarray);
3756-
3757- ASSERT_TRUE(got_app_isolation);
3758- ASSERT_TRUE(got_cache_home);
3759- ASSERT_TRUE(got_config_home);
3760- ASSERT_TRUE(got_data_home);
3761- ASSERT_TRUE(got_runtime_dir);
3762- ASSERT_TRUE(got_data_dirs);
3763- ASSERT_TRUE(got_temp_dir);
3764- ASSERT_TRUE(got_shader_dir);
3765-
3766- g_object_unref(bus);
3767- g_object_unref(mock);
3768- g_object_unref(service);
3769-
3770- return;
3771-}
3772-
3773 TEST_F(HelperTest, DesktopToExec)
3774 {
3775 GKeyFile * keyfile = NULL;
3776
3777=== modified file 'tests/libual-cpp-test.cc'
3778--- tests/libual-cpp-test.cc 2017-03-09 16:05:36 +0000
3779+++ tests/libual-cpp-test.cc 2017-03-21 03:20:55 +0000
3780@@ -32,6 +32,7 @@
3781 #include "application.h"
3782 #include "glib-thread.h"
3783 #include "helper.h"
3784+#include "jobs-base.h"
3785 #include "registry.h"
3786 #include "ubuntu-app-launch.h"
3787
3788@@ -39,6 +40,8 @@
3789 #include "libertine-service.h"
3790 #include "mir-mock.h"
3791 #include "spew-master.h"
3792+#include "systemd-mock.h"
3793+#include "zg-mock.h"
3794
3795 #ifdef ENABLE_SNAPPY
3796 #include "snapd-mock.h"
3797@@ -46,6 +49,8 @@
3798 #define LOCAL_SNAPD_TEST_SOCKET (SNAPD_TEST_SOCKET "-libual-cpp-test")
3799 #endif
3800
3801+#define CGROUP_DIR (CMAKE_BINARY_DIR "/systemd-cgroups")
3802+
3803 class LibUAL : public EventuallyFixture
3804 {
3805 protected:
3806@@ -53,6 +58,7 @@
3807 DbusTestDbusMock* mock = NULL;
3808 DbusTestDbusMock* cgmock = NULL;
3809 std::shared_ptr<LibertineService> libertine;
3810+ std::shared_ptr<SystemdMock> systemd;
3811 GDBusConnection* bus = NULL;
3812 guint resume_timeout = 0;
3813 std::shared_ptr<ubuntu::app_launch::Registry> registry;
3814@@ -160,156 +166,25 @@
3815 g_unlink(LOCAL_SNAPD_TEST_SOCKET);
3816 #endif
3817 g_setenv("UBUNTU_APP_LAUNCH_SYSTEMD_PATH", "/this/should/not/exist", TRUE);
3818+ /* Setting the cgroup temp directory */
3819+ g_setenv("UBUNTU_APP_LAUNCH_SYSTEMD_CGROUP_ROOT", CGROUP_DIR, TRUE);
3820
3821 service = dbus_test_service_new(NULL);
3822
3823 debugConnection();
3824
3825- mock = dbus_test_dbus_mock_new("com.ubuntu.Upstart");
3826-
3827- DbusTestDbusMockObject* obj =
3828- dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);
3829-
3830- dbus_test_dbus_mock_object_add_method(mock, obj, "EmitEvent", G_VARIANT_TYPE("(sasb)"), NULL, "", NULL);
3831-
3832- dbus_test_dbus_mock_object_add_method(mock, obj, "GetJobByName", G_VARIANT_TYPE("s"), G_VARIANT_TYPE("o"),
3833- "if args[0] == 'application-click':\n"
3834- " ret = dbus.ObjectPath('/com/test/application_click')\n"
3835- "elif args[0] == 'application-snap':\n"
3836- " ret = dbus.ObjectPath('/com/test/application_snap')\n"
3837- "elif args[0] == 'application-legacy':\n"
3838- " ret = dbus.ObjectPath('/com/test/application_legacy')\n"
3839- "elif args[0] == 'untrusted-helper':\n"
3840- " ret = dbus.ObjectPath('/com/test/untrusted/helper')\n",
3841- NULL);
3842-
3843- dbus_test_dbus_mock_object_add_method(mock, obj, "SetEnv", G_VARIANT_TYPE("(assb)"), NULL, "", NULL);
3844-
3845- /* Click App */
3846- DbusTestDbusMockObject* jobobj =
3847- dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
3848-
3849- dbus_test_dbus_mock_object_add_method(
3850- mock, jobobj, "Start", G_VARIANT_TYPE("(asb)"), NULL,
3851- "if 'APP_ID=com.test.good_application_1.2.3' in args[0]:"
3852- " raise dbus.exceptions.DBusException('Foo running', name='com.ubuntu.Upstart0_6.Error.AlreadyStarted')",
3853- NULL);
3854-
3855- dbus_test_dbus_mock_object_add_method(mock, jobobj, "Stop", G_VARIANT_TYPE("(asb)"), NULL, "", NULL);
3856-
3857- dbus_test_dbus_mock_object_add_method(mock, jobobj, "GetAllInstances", NULL, G_VARIANT_TYPE("ao"),
3858- "ret = [ dbus.ObjectPath('/com/test/app_instance') ]", NULL);
3859-
3860- dbus_test_dbus_mock_object_add_method(mock, jobobj, "GetInstanceByName", G_VARIANT_TYPE_STRING,
3861- G_VARIANT_TYPE("o"), "ret = dbus.ObjectPath('/com/test/app_instance')",
3862- NULL);
3863-
3864- DbusTestDbusMockObject* instobj =
3865- dbus_test_dbus_mock_get_object(mock, "/com/test/app_instance", "com.ubuntu.Upstart0_6.Instance", NULL);
3866- dbus_test_dbus_mock_object_add_property(mock, instobj, "name", G_VARIANT_TYPE_STRING,
3867- g_variant_new_string("com.test.good_application_1.2.3"), NULL);
3868- gchar* process_var = g_strdup_printf("[('main', %d)]", getpid());
3869- dbus_test_dbus_mock_object_add_property(mock, instobj, "processes", G_VARIANT_TYPE("a(si)"),
3870- g_variant_new_parsed(process_var), NULL);
3871- g_free(process_var);
3872-
3873-#ifdef ENABLE_SNAPPY
3874- /* Snap App */
3875- auto snapjobobj =
3876- dbus_test_dbus_mock_get_object(mock, "/com/test/application_snap", "com.ubuntu.Upstart0_6.Job", NULL);
3877-
3878- dbus_test_dbus_mock_object_add_method(
3879- mock, snapjobobj, "Start", G_VARIANT_TYPE("(asb)"), NULL,
3880- "if args[0][0] == 'APP_ID=unity8-package_foo_x123':"
3881- " raise dbus.exceptions.DBusException('Foo running', name='com.ubuntu.Upstart0_6.Error.AlreadyStarted')",
3882- NULL);
3883-
3884- dbus_test_dbus_mock_object_add_method(mock, snapjobobj, "Stop", G_VARIANT_TYPE("(asb)"), NULL, "", NULL);
3885-
3886- dbus_test_dbus_mock_object_add_method(mock, snapjobobj, "GetAllInstances", NULL, G_VARIANT_TYPE("ao"),
3887- "ret = [ dbus.ObjectPath('/com/test/snapp_instance') ]", NULL);
3888-
3889- dbus_test_dbus_mock_object_add_method(mock, snapjobobj, "GetInstanceByName", G_VARIANT_TYPE_STRING,
3890- G_VARIANT_TYPE("o"), "ret = dbus.ObjectPath('/com/test/snapp_instance')",
3891- NULL);
3892-
3893- auto snapinstobj =
3894- dbus_test_dbus_mock_get_object(mock, "/com/test/snapp_instance", "com.ubuntu.Upstart0_6.Instance", NULL);
3895- dbus_test_dbus_mock_object_add_property(mock, snapinstobj, "name", G_VARIANT_TYPE_STRING,
3896- g_variant_new_string("unity8-package_foo_x123-"), NULL);
3897- gchar* snapprocess_var = g_strdup_printf("[('main', %d)]", getpid());
3898- dbus_test_dbus_mock_object_add_property(mock, snapinstobj, "processes", G_VARIANT_TYPE("a(si)"),
3899- g_variant_new_parsed(snapprocess_var), NULL);
3900- g_free(snapprocess_var);
3901-#endif
3902-
3903- /* Legacy App */
3904- DbusTestDbusMockObject* ljobobj =
3905- dbus_test_dbus_mock_get_object(mock, "/com/test/application_legacy", "com.ubuntu.Upstart0_6.Job", NULL);
3906-
3907- dbus_test_dbus_mock_object_add_method(mock, ljobobj, "Start", G_VARIANT_TYPE("(asb)"), NULL, "", NULL);
3908-
3909- dbus_test_dbus_mock_object_add_method(mock, ljobobj, "Stop", G_VARIANT_TYPE("(asb)"), NULL, "", NULL);
3910-
3911- dbus_test_dbus_mock_object_add_method(mock, ljobobj, "GetAllInstances", NULL, G_VARIANT_TYPE("ao"),
3912- "ret = [ dbus.ObjectPath('/com/test/legacy_app_instance'), "
3913- "dbus.ObjectPath('/com/test/legacy_app_instance2') ]",
3914- NULL);
3915-
3916- dbus_test_dbus_mock_object_add_method(mock, ljobobj, "GetInstanceByName", G_VARIANT_TYPE_STRING,
3917- G_VARIANT_TYPE("o"),
3918- "ret = dbus.ObjectPath('/com/test/legacy_app_instance')", NULL);
3919-
3920- DbusTestDbusMockObject* linstobj = dbus_test_dbus_mock_get_object(mock, "/com/test/legacy_app_instance",
3921- "com.ubuntu.Upstart0_6.Instance", NULL);
3922- dbus_test_dbus_mock_object_add_property(mock, linstobj, "name", G_VARIANT_TYPE_STRING,
3923- g_variant_new_string("multiple-2342345"), NULL);
3924- dbus_test_dbus_mock_object_add_property(mock, linstobj, "processes", G_VARIANT_TYPE("a(si)"),
3925- g_variant_new_parsed("[('main', 5678)]"), NULL);
3926-
3927- DbusTestDbusMockObject* linstobj2 = dbus_test_dbus_mock_get_object(mock, "/com/test/legacy_app_instance2",
3928- "com.ubuntu.Upstart0_6.Instance", NULL);
3929- dbus_test_dbus_mock_object_add_property(mock, linstobj2, "name", G_VARIANT_TYPE_STRING,
3930- g_variant_new_string("single-"), NULL);
3931- dbus_test_dbus_mock_object_add_property(mock, linstobj2, "processes", G_VARIANT_TYPE("a(si)"),
3932- g_variant_new_parsed("[('main', 5678)]"), NULL);
3933-
3934- /* Untrusted Helper */
3935- DbusTestDbusMockObject* uhelperobj =
3936- dbus_test_dbus_mock_get_object(mock, "/com/test/untrusted/helper", "com.ubuntu.Upstart0_6.Job", NULL);
3937-
3938- dbus_test_dbus_mock_object_add_method(mock, uhelperobj, "Start", G_VARIANT_TYPE("(asb)"), NULL, "", NULL);
3939-
3940- dbus_test_dbus_mock_object_add_method(mock, uhelperobj, "Stop", G_VARIANT_TYPE("(asb)"), NULL, "", NULL);
3941-
3942- dbus_test_dbus_mock_object_add_method(mock, uhelperobj, "GetAllInstances", NULL, G_VARIANT_TYPE("ao"),
3943- "ret = [ dbus.ObjectPath('/com/test/untrusted/helper/instance'), "
3944- "dbus.ObjectPath('/com/test/untrusted/helper/multi_instance') ]",
3945- NULL);
3946-
3947- DbusTestDbusMockObject* uhelperinstance = dbus_test_dbus_mock_get_object(
3948- mock, "/com/test/untrusted/helper/instance", "com.ubuntu.Upstart0_6.Instance", NULL);
3949- dbus_test_dbus_mock_object_add_property(mock, uhelperinstance, "name", G_VARIANT_TYPE_STRING,
3950- g_variant_new_string("untrusted-type::com.foo_bar_43.23.12"), NULL);
3951-
3952- DbusTestDbusMockObject* unhelpermulti = dbus_test_dbus_mock_get_object(
3953- mock, "/com/test/untrusted/helper/multi_instance", "com.ubuntu.Upstart0_6.Instance", NULL);
3954- dbus_test_dbus_mock_object_add_property(
3955- mock, unhelpermulti, "name", G_VARIANT_TYPE_STRING,
3956- g_variant_new_string("untrusted-type:24034582324132:com.bar_foo_8432.13.1"), NULL);
3957-
3958- /* Create the cgroup manager mock */
3959- cgmock = dbus_test_dbus_mock_new("org.test.cgmock");
3960- g_setenv("UBUNTU_APP_LAUNCH_CG_MANAGER_NAME", "org.test.cgmock", TRUE);
3961-
3962- DbusTestDbusMockObject* cgobject = dbus_test_dbus_mock_get_object(cgmock, "/org/linuxcontainers/cgmanager",
3963- "org.linuxcontainers.cgmanager0_0", NULL);
3964- dbus_test_dbus_mock_object_add_method(cgmock, cgobject, "GetTasksRecursive", G_VARIANT_TYPE("(ss)"),
3965- G_VARIANT_TYPE("ai"), "ret = [100, 200, 300]", NULL);
3966+ systemd = std::make_shared<SystemdMock>(
3967+ std::list<SystemdMock::Instance>{
3968+ {"application-click", "com.test.good_application_1.2.3", {}, getpid(), {100, 200, 300}},
3969+ {"application-snap", "unity8-package_foo_x123", {}, getpid(), {100, 200, 300}},
3970+ {"application-legacy", "multiple", "2342345", 5678, {100, 200, 300}},
3971+ {"application-legacy", "single", {}, 5678, {100, 200, 300}},
3972+ {"helper", "com.foo_bar_43.23.12", {}, 1, {100, 200, 300}},
3973+ {"helper", "com.bar_foo_8432.13.1", "24034582324132", 1, {100, 200, 300}}},
3974+ CGROUP_DIR);
3975
3976 /* Put it together */
3977- dbus_test_service_add_task(service, DBUS_TEST_TASK(mock));
3978- dbus_test_service_add_task(service, DBUS_TEST_TASK(cgmock));
3979+ dbus_test_service_add_task(service, *systemd);
3980
3981 /* Add in Libertine */
3982 libertine = std::make_shared<LibertineService>();
3983@@ -343,9 +218,8 @@
3984 //
3985 // ubuntu::app_launch::Registry::clearDefault();
3986
3987+ systemd.reset();
3988 libertine.reset();
3989- g_clear_object(&mock);
3990- g_clear_object(&cgmock);
3991 g_clear_object(&service);
3992
3993 g_object_unref(bus);
3994@@ -357,63 +231,40 @@
3995 #endif
3996 }
3997
3998- GVariant* find_env(GVariant* env_array, const gchar* var)
3999- {
4000- unsigned int i;
4001- GVariant* retval = nullptr;
4002-
4003- for (i = 0; i < g_variant_n_children(env_array); i++)
4004- {
4005- GVariant* child = g_variant_get_child_value(env_array, i);
4006- const gchar* envvar = g_variant_get_string(child, nullptr);
4007-
4008- if (g_str_has_prefix(envvar, var))
4009- {
4010- if (retval != nullptr)
4011- {
4012- g_warning("Found the env var more than once!");
4013- g_variant_unref(retval);
4014- return nullptr;
4015- }
4016-
4017- retval = child;
4018- }
4019- else
4020- {
4021- g_variant_unref(child);
4022- }
4023- }
4024-
4025- if (!retval)
4026- {
4027- gchar* envstr = g_variant_print(env_array, FALSE);
4028- g_warning("Unable to find '%s' in '%s'", var, envstr);
4029- g_free(envstr);
4030- }
4031-
4032- return retval;
4033- }
4034-
4035- bool check_env(GVariant* env_array, const gchar* var, const gchar* value)
4036- {
4037- bool found = false;
4038- GVariant* val = find_env(env_array, var);
4039- if (val == nullptr)
4040+ static std::string find_env(std::set<std::string>& envs, std::string var)
4041+ {
4042+ auto iter =
4043+ std::find_if(envs.begin(), envs.end(), [var](std::string value) { return split_env(value).first == var; });
4044+
4045+ if (iter == envs.end())
4046+ {
4047+ return {};
4048+ }
4049+ else
4050+ {
4051+ return *iter;
4052+ }
4053+ }
4054+
4055+ static std::pair<std::string, std::string> split_env(const std::string& env)
4056+ {
4057+ auto eq = std::find(env.begin(), env.end(), '=');
4058+ if (eq == env.end())
4059+ {
4060+ throw std::runtime_error{"Environment value is invalid: " + env};
4061+ }
4062+
4063+ return std::make_pair(std::string(env.begin(), eq), std::string(eq + 1, env.end()));
4064+ }
4065+
4066+ static bool check_env(std::set<std::string>& envs, const std::string& key, const std::string& value)
4067+ {
4068+ auto val = find_env(envs, key);
4069+ if (val.empty())
4070 {
4071 return false;
4072 }
4073-
4074- const gchar* envvar = g_variant_get_string(val, nullptr);
4075-
4076- gchar* combined = g_strdup_printf("%s=%s", var, value);
4077- if (g_strcmp0(envvar, combined) == 0)
4078- {
4079- found = true;
4080- }
4081-
4082- g_variant_unref(val);
4083-
4084- return found;
4085+ return split_env(val).second == value;
4086 }
4087 };
4088
4089@@ -423,107 +274,6 @@
4090 [&task] { return dbus_test_task_get_state(DBUS_TEST_TASK(task)); } \
4091 }
4092
4093-TEST_F(LibUAL, StartClickApplication)
4094-{
4095- DbusTestDbusMockObject* obj =
4096- dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
4097-
4098- /* Basic make sure we can send the event */
4099- auto appid = ubuntu::app_launch::AppID::parse("com.test.multiple_first_1.2.3");
4100- auto app = ubuntu::app_launch::Application::create(appid, registry);
4101- app->launch();
4102-
4103- EXPECT_EQ(1, dbus_test_dbus_mock_object_check_method_call(mock, obj, "Start", NULL, NULL));
4104-
4105- ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
4106-
4107- /* Now look at the details of the call */
4108- app->launch();
4109-
4110- guint len = 0;
4111- const DbusTestDbusMockCall* calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
4112- EXPECT_NE(nullptr, calls);
4113- ASSERT_EQ(1u, len);
4114-
4115- EXPECT_STREQ("Start", calls->name);
4116- EXPECT_EQ(2u, g_variant_n_children(calls->params));
4117-
4118- GVariant* block = g_variant_get_child_value(calls->params, 1);
4119- EXPECT_TRUE(g_variant_get_boolean(block));
4120- g_variant_unref(block);
4121-
4122- GVariant* env = g_variant_get_child_value(calls->params, 0);
4123- EXPECT_TRUE(check_env(env, "APP_ID", "com.test.multiple_first_1.2.3"));
4124- g_variant_unref(env);
4125-
4126- ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
4127-
4128- /* Let's pass some URLs */
4129- std::vector<ubuntu::app_launch::Application::URL> urls{
4130- ubuntu::app_launch::Application::URL::from_raw("http://ubuntu.com/"),
4131- ubuntu::app_launch::Application::URL::from_raw("https://ubuntu.com/"),
4132- ubuntu::app_launch::Application::URL::from_raw("file:///home/phablet/test.txt")};
4133-
4134- app->launch(urls);
4135-
4136- len = 0;
4137- calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
4138- EXPECT_NE(nullptr, calls);
4139- ASSERT_EQ(1u, len);
4140-
4141- env = g_variant_get_child_value(calls->params, 0);
4142- EXPECT_TRUE(check_env(env, "APP_ID", "com.test.multiple_first_1.2.3"));
4143- EXPECT_TRUE(
4144- check_env(env, "APP_URIS", "'http://ubuntu.com/' 'https://ubuntu.com/' 'file:///home/phablet/test.txt'"));
4145- g_variant_unref(env);
4146-
4147- return;
4148-}
4149-
4150-TEST_F(LibUAL, StartClickApplicationTest)
4151-{
4152- DbusTestDbusMockObject* obj =
4153- dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
4154-
4155- /* Basic make sure we can send the event */
4156- auto appid = ubuntu::app_launch::AppID::parse("com.test.multiple_first_1.2.3");
4157- auto app = ubuntu::app_launch::Application::create(appid, registry);
4158- app->launchTest();
4159-
4160- guint len = 0;
4161- const DbusTestDbusMockCall* calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
4162- EXPECT_NE(nullptr, calls);
4163- ASSERT_EQ(1u, len);
4164-
4165- EXPECT_STREQ("Start", calls->name);
4166- EXPECT_EQ(2u, g_variant_n_children(calls->params));
4167-
4168- GVariant* block = g_variant_get_child_value(calls->params, 1);
4169- EXPECT_TRUE(g_variant_get_boolean(block));
4170- g_variant_unref(block);
4171-
4172- GVariant* env = g_variant_get_child_value(calls->params, 0);
4173- EXPECT_TRUE(check_env(env, "APP_ID", "com.test.multiple_first_1.2.3"));
4174- EXPECT_TRUE(check_env(env, "QT_LOAD_TESTABILITY", "1"));
4175- g_variant_unref(env);
4176-}
4177-
4178-TEST_F(LibUAL, StopClickApplication)
4179-{
4180- DbusTestDbusMockObject* obj =
4181- dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
4182-
4183- auto appid = ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3");
4184- auto app = ubuntu::app_launch::Application::create(appid, registry);
4185-
4186- ASSERT_TRUE(app->hasInstances());
4187- ASSERT_EQ(1, int(app->instances().size()));
4188-
4189- app->instances()[0]->stop();
4190-
4191- ASSERT_EQ(dbus_test_dbus_mock_object_check_method_call(mock, obj, "Stop", NULL, NULL), 1);
4192-}
4193-
4194 #ifdef ENABLE_SNAPPY
4195 /* Snapd mock data */
4196 static std::pair<std::string, std::string> interfaces{
4197@@ -617,113 +367,6 @@
4198 FAIL() << "Expected std::runtime_error";
4199 }
4200 }
4201-
4202-TEST_F(LibUAL, StartSnapApplication)
4203-{
4204- SnapdMock snapd{LOCAL_SNAPD_TEST_SOCKET, {u8Package, interfaces, u8Package}};
4205- registry = std::make_shared<ubuntu::app_launch::Registry>();
4206-
4207- auto obj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_snap", "com.ubuntu.Upstart0_6.Job", NULL);
4208-
4209- /* Basic make sure we can send the event */
4210- auto appid = ubuntu::app_launch::AppID::parse("unity8-package_single_x123");
4211- auto app = ubuntu::app_launch::Application::create(appid, registry);
4212- app->launch();
4213-
4214- EXPECT_EQ(1, dbus_test_dbus_mock_object_check_method_call(mock, obj, "Start", NULL, NULL));
4215-
4216- ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
4217-
4218- /* Now look at the details of the call */
4219- app->launch();
4220-
4221- guint len = 0;
4222- const DbusTestDbusMockCall* calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
4223- EXPECT_NE(nullptr, calls);
4224- EXPECT_EQ(1u, len);
4225-
4226- EXPECT_STREQ("Start", calls->name);
4227- EXPECT_EQ(2u, g_variant_n_children(calls->params));
4228-
4229- GVariant* block = g_variant_get_child_value(calls->params, 1);
4230- EXPECT_TRUE(g_variant_get_boolean(block));
4231- g_variant_unref(block);
4232-
4233- GVariant* env = g_variant_get_child_value(calls->params, 0);
4234- EXPECT_TRUE(check_env(env, "APP_ID", "unity8-package_single_x123"));
4235- g_variant_unref(env);
4236-
4237- ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
4238-
4239- /* Let's pass some URLs */
4240- std::vector<ubuntu::app_launch::Application::URL> urls{
4241- ubuntu::app_launch::Application::URL::from_raw("http://ubuntu.com/"),
4242- ubuntu::app_launch::Application::URL::from_raw("https://ubuntu.com/"),
4243- ubuntu::app_launch::Application::URL::from_raw("file:///home/phablet/test.txt")};
4244-
4245- app->launch(urls);
4246-
4247- len = 0;
4248- calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
4249- EXPECT_NE(nullptr, calls);
4250- EXPECT_EQ(1u, len);
4251-
4252- env = g_variant_get_child_value(calls->params, 0);
4253- EXPECT_TRUE(check_env(env, "APP_ID", "unity8-package_single_x123"));
4254- EXPECT_TRUE(
4255- check_env(env, "APP_URIS", "'http://ubuntu.com/' 'https://ubuntu.com/' 'file:///home/phablet/test.txt'"));
4256- g_variant_unref(env);
4257-
4258- return;
4259-}
4260-
4261-TEST_F(LibUAL, StartSnapApplicationTest)
4262-{
4263- SnapdMock snapd{LOCAL_SNAPD_TEST_SOCKET, {u8Package, interfaces, u8Package}};
4264- registry = std::make_shared<ubuntu::app_launch::Registry>();
4265-
4266- auto obj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_snap", "com.ubuntu.Upstart0_6.Job", NULL);
4267-
4268- /* Basic make sure we can send the event */
4269- auto appid = ubuntu::app_launch::AppID::parse("unity8-package_single_x123");
4270- auto app = ubuntu::app_launch::Application::create(appid, registry);
4271- app->launchTest();
4272-
4273- guint len = 0;
4274- auto calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
4275- EXPECT_NE(nullptr, calls);
4276- EXPECT_EQ(1u, len);
4277-
4278- EXPECT_STREQ("Start", calls->name);
4279- EXPECT_EQ(2u, g_variant_n_children(calls->params));
4280-
4281- GVariant* block = g_variant_get_child_value(calls->params, 1);
4282- EXPECT_TRUE(g_variant_get_boolean(block));
4283- g_variant_unref(block);
4284-
4285- GVariant* env = g_variant_get_child_value(calls->params, 0);
4286- EXPECT_TRUE(check_env(env, "APP_ID", "unity8-package_single_x123"));
4287- EXPECT_TRUE(check_env(env, "QT_LOAD_TESTABILITY", "1"));
4288- g_variant_unref(env);
4289-}
4290-
4291-TEST_F(LibUAL, StopSnapApplication)
4292-{
4293- SnapdMock snapd{LOCAL_SNAPD_TEST_SOCKET, {u8Package, interfaces, u8Package}};
4294- registry = std::make_shared<ubuntu::app_launch::Registry>();
4295-
4296- auto obj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_snap", "com.ubuntu.Upstart0_6.Job", NULL);
4297-
4298- auto appid = ubuntu::app_launch::AppID::parse("unity8-package_foo_x123");
4299- auto app = ubuntu::app_launch::Application::create(appid, registry);
4300-
4301- ASSERT_TRUE(app->hasInstances());
4302- EXPECT_EQ(1, int(app->instances().size()));
4303-
4304- app->instances()[0]->stop();
4305-
4306- ASSERT_EQ(dbus_test_dbus_mock_object_check_method_call(mock, obj, "Stop", NULL, NULL), 1);
4307-}
4308 #endif
4309
4310 TEST_F(LibUAL, ApplicationPid)
4311@@ -892,107 +535,6 @@
4312 #endif
4313 }
4314
4315-TEST_F(LibUAL, StartStopObserver)
4316-{
4317- int start_count = 0;
4318- int stop_count = 0;
4319- ubuntu::app_launch::AppID start_appid;
4320- ubuntu::app_launch::AppID stop_appid;
4321-
4322- ubuntu::app_launch::Registry::appStarted(registry).connect(
4323- [&start_count, &start_appid](std::shared_ptr<ubuntu::app_launch::Application> app,
4324- std::shared_ptr<ubuntu::app_launch::Application::Instance> instance) {
4325- if (!start_appid.empty() && !(start_appid == app->appId()))
4326- return;
4327-
4328- start_count++;
4329- });
4330-
4331- ubuntu::app_launch::Registry::appStopped(registry).connect(
4332- [&stop_count, &stop_appid](std::shared_ptr<ubuntu::app_launch::Application> app,
4333- std::shared_ptr<ubuntu::app_launch::Application::Instance> instance) {
4334- if (!stop_appid.empty() && !(stop_appid == app->appId()))
4335- return;
4336-
4337- stop_count++;
4338- });
4339-
4340- DbusTestDbusMockObject* obj =
4341- dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);
4342-
4343- /* Basic start */
4344- dbus_test_dbus_mock_object_emit_signal(
4345- mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),
4346- g_variant_new_parsed("('started', ['JOB=application-click', 'INSTANCE=com.test.good_application_1.2.3'])"),
4347- NULL);
4348-
4349- EXPECT_EVENTUALLY_EQ(1, start_count);
4350-
4351- /* Basic stop */
4352- dbus_test_dbus_mock_object_emit_signal(
4353- mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),
4354- g_variant_new_parsed("('stopped', ['JOB=application-click', 'INSTANCE=com.test.good_application_1.2.3'])"),
4355- NULL);
4356-
4357- EXPECT_EVENTUALLY_EQ(1, stop_count);
4358-
4359- /* Start legacy */
4360- start_count = 0;
4361- start_appid = ubuntu::app_launch::AppID{ubuntu::app_launch::AppID::Package::from_raw({}),
4362- ubuntu::app_launch::AppID::AppName::from_raw("multiple"),
4363- ubuntu::app_launch::AppID::Version::from_raw({})};
4364-
4365- dbus_test_dbus_mock_object_emit_signal(
4366- mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),
4367- g_variant_new_parsed("('started', ['JOB=application-legacy', 'INSTANCE=multiple-234235'])"), NULL);
4368-
4369- EXPECT_EVENTUALLY_EQ(1, start_count);
4370-
4371- /* Legacy stop */
4372- stop_count = 0;
4373- stop_appid = ubuntu::app_launch::AppID{ubuntu::app_launch::AppID::Package::from_raw({}),
4374- ubuntu::app_launch::AppID::AppName::from_raw("foo"),
4375- ubuntu::app_launch::AppID::Version::from_raw({})};
4376-
4377- dbus_test_dbus_mock_object_emit_signal(
4378- mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),
4379- g_variant_new_parsed("('stopped', ['JOB=application-legacy', 'INSTANCE=foo-9344321'])"), NULL);
4380-
4381- EXPECT_EVENTUALLY_EQ(1, stop_count);
4382-
4383- /* Test Noise Start */
4384- start_count = 0;
4385- start_appid = ubuntu::app_launch::AppID{ubuntu::app_launch::AppID::Package::from_raw("com.test.good"),
4386- ubuntu::app_launch::AppID::AppName::from_raw("application"),
4387- ubuntu::app_launch::AppID::Version::from_raw("1.2.3")};
4388- stop_count = 0;
4389- stop_appid = ubuntu::app_launch::AppID{ubuntu::app_launch::AppID::Package::from_raw("com.test.good"),
4390- ubuntu::app_launch::AppID::AppName::from_raw("application"),
4391- ubuntu::app_launch::AppID::Version::from_raw("1.2.3")};
4392-
4393- /* A full lifecycle */
4394- dbus_test_dbus_mock_object_emit_signal(
4395- mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),
4396- g_variant_new_parsed("('starting', ['JOB=application-click', 'INSTANCE=com.test.good_application_1.2.3'])"),
4397- NULL);
4398- dbus_test_dbus_mock_object_emit_signal(
4399- mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),
4400- g_variant_new_parsed("('started', ['JOB=application-click', 'INSTANCE=com.test.good_application_1.2.3'])"),
4401- NULL);
4402- dbus_test_dbus_mock_object_emit_signal(
4403- mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),
4404- g_variant_new_parsed("('stopping', ['JOB=application-click', 'INSTANCE=com.test.good_application_1.2.3'])"),
4405- NULL);
4406- dbus_test_dbus_mock_object_emit_signal(
4407- mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),
4408- g_variant_new_parsed("('stopped', ['JOB=application-click', 'INSTANCE=com.test.good_application_1.2.3'])"),
4409- NULL);
4410-
4411- /* Ensure we just signaled once for each */
4412- EXPECT_EVENTUALLY_EQ(1, start_count);
4413- EXPECT_EVENTUALLY_EQ(1, stop_count);
4414-}
4415-
4416 TEST_F(LibUAL, StartingResponses)
4417 {
4418 /* Get Bus */
4419@@ -1195,186 +737,100 @@
4420
4421 TEST_F(LibUAL, LegacySingleInstance)
4422 {
4423- DbusTestDbusMockObject* obj =
4424- dbus_test_dbus_mock_get_object(mock, "/com/test/application_legacy", "com.ubuntu.Upstart0_6.Job", NULL);
4425-
4426 /* Check for a single-instance app */
4427 auto singleappid = ubuntu::app_launch::AppID::find(registry, "single");
4428 auto singleapp = ubuntu::app_launch::Application::create(singleappid, registry);
4429
4430 singleapp->launch();
4431
4432- guint len = 0;
4433- const DbusTestDbusMockCall* calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
4434- EXPECT_NE(nullptr, calls);
4435- ASSERT_EQ(1u, len);
4436-
4437- EXPECT_STREQ("Start", calls->name);
4438- EXPECT_EQ(2u, g_variant_n_children(calls->params));
4439-
4440- GVariant* block = g_variant_get_child_value(calls->params, 1);
4441- EXPECT_TRUE(g_variant_get_boolean(block));
4442- g_variant_unref(block);
4443-
4444- GVariant* env = g_variant_get_child_value(calls->params, 0);
4445- EXPECT_TRUE(check_env(env, "APP_ID", "single"));
4446- EXPECT_TRUE(check_env(env, "INSTANCE_ID", ""));
4447- g_variant_unref(env);
4448-
4449- ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
4450+ auto singleStart = systemd->unitCalls();
4451+ ASSERT_EQ(1u, singleStart.size());
4452+ EXPECT_EQ(SystemdMock::instanceName({"application-legacy", "single", "", 0, {}}), singleStart.begin()->name);
4453+
4454+ systemd->managerClear();
4455
4456 /* Check for a multi-instance app */
4457 auto multipleappid = ubuntu::app_launch::AppID::find(registry, "multiple");
4458 auto multipleapp = ubuntu::app_launch::Application::create(multipleappid, registry);
4459
4460- multipleapp->launch();
4461-
4462- len = 0;
4463- calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
4464- EXPECT_NE(nullptr, calls);
4465- ASSERT_EQ(1u, len);
4466-
4467- EXPECT_STREQ("Start", calls->name);
4468- EXPECT_EQ(2u, g_variant_n_children(calls->params));
4469-
4470- block = g_variant_get_child_value(calls->params, 1);
4471- EXPECT_TRUE(g_variant_get_boolean(block));
4472- g_variant_unref(block);
4473-
4474- env = g_variant_get_child_value(calls->params, 0);
4475- EXPECT_TRUE(check_env(env, "APP_ID", "multiple"));
4476- EXPECT_FALSE(check_env(env, "INSTANCE_ID", ""));
4477- g_variant_unref(env);
4478-}
4479-
4480-TEST_F(LibUAL, FailingObserver)
4481-{
4482- ubuntu::app_launch::AppID lastFailedApp;
4483- ubuntu::app_launch::Registry::FailureType lastFailedType;
4484-
4485- ubuntu::app_launch::Registry::appFailed(registry).connect(
4486- [&lastFailedApp, &lastFailedType](std::shared_ptr<ubuntu::app_launch::Application> app,
4487- std::shared_ptr<ubuntu::app_launch::Application::Instance> instance,
4488- ubuntu::app_launch::Registry::FailureType type) {
4489- lastFailedApp = app->appId();
4490- lastFailedType = type;
4491- });
4492-
4493- GDBusConnection* session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
4494-
4495- g_dbus_connection_emit_signal(
4496- session, NULL, /* destination */
4497- "/", /* path */
4498- "com.canonical.UbuntuAppLaunch", /* interface */
4499- "ApplicationFailed", /* signal */
4500- g_variant_new("(sss)", "com.test.good_application_1.2.3", "goodinstance", "crash"), /* params, the same */
4501- NULL);
4502-
4503- EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"), lastFailedApp);
4504- EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::Registry::FailureType::CRASH, lastFailedType);
4505-
4506- lastFailedApp = ubuntu::app_launch::AppID();
4507-
4508- g_dbus_connection_emit_signal(
4509- session, NULL, /* destination */
4510- "/", /* path */
4511- "com.canonical.UbuntuAppLaunch", /* interface */
4512- "ApplicationFailed", /* signal */
4513- g_variant_new("(sss)", "com.test.good_application_1.2.3", "goodinstance", "blahblah"), /* params, the same */
4514- NULL);
4515-
4516- EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"), lastFailedApp);
4517-
4518- lastFailedApp = ubuntu::app_launch::AppID();
4519-
4520- g_dbus_connection_emit_signal(session, NULL, /* destination */
4521- "/", /* path */
4522- "com.canonical.UbuntuAppLaunch", /* interface */
4523- "ApplicationFailed", /* signal */
4524- g_variant_new("(sss)", "com.test.good_application_1.2.3", "goodinstance",
4525- "start-failure"), /* params, the same */
4526- NULL);
4527-
4528- EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::Registry::FailureType::START_FAILURE, lastFailedType);
4529-
4530- g_object_unref(session);
4531+ auto inst = multipleapp->launch();
4532+
4533+ auto multiStart = systemd->unitCalls();
4534+ ASSERT_EQ(1u, multiStart.size());
4535+ EXPECT_EQ(SystemdMock::instanceName(
4536+ {"application-legacy",
4537+ "multiple",
4538+ std::dynamic_pointer_cast<ubuntu::app_launch::jobs::instance::Base>(inst)->getInstanceId(),
4539+ 0,
4540+ {}}),
4541+ multiStart.begin()->name);
4542 }
4543
4544 TEST_F(LibUAL, StartHelper)
4545 {
4546- DbusTestDbusMockObject* obj =
4547- dbus_test_dbus_mock_get_object(mock, "/com/test/untrusted/helper", "com.ubuntu.Upstart0_6.Job", NULL);
4548-
4549 auto untrusted = ubuntu::app_launch::Helper::Type::from_raw("untrusted-type");
4550
4551 /* Basic make sure we can send the event */
4552 auto appid = ubuntu::app_launch::AppID::parse("com.test.multiple_first_1.2.3");
4553 auto helper = ubuntu::app_launch::Helper::create(untrusted, appid, registry);
4554
4555- helper->launch();
4556-
4557- EXPECT_EQ(1, dbus_test_dbus_mock_object_check_method_call(mock, obj, "Start", NULL, NULL));
4558-
4559- ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
4560+ auto inst = helper->launch();
4561+
4562+ auto helperStart = systemd->unitCalls();
4563+
4564+ ASSERT_EQ(1u, helperStart.size());
4565+ EXPECT_EQ(SystemdMock::instanceName(
4566+ {"untrusted-type",
4567+ "com.test.multiple_first_1.2.3",
4568+ std::dynamic_pointer_cast<ubuntu::app_launch::jobs::instance::Base>(inst)->getInstanceId(),
4569+ 0,
4570+ {}}),
4571+ helperStart.begin()->name);
4572+
4573+ systemd->managerClear();
4574
4575 /* Now check a multi out */
4576- helper->launch();
4577-
4578- guint len = 0;
4579- auto calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
4580- EXPECT_NE(nullptr, calls);
4581- ASSERT_EQ(1u, len);
4582-
4583- EXPECT_STREQ("Start", calls->name);
4584- EXPECT_EQ(2u, g_variant_n_children(calls->params));
4585-
4586- auto block = g_variant_get_child_value(calls->params, 1);
4587- EXPECT_TRUE(g_variant_get_boolean(block));
4588- g_variant_unref(block);
4589-
4590- auto env = g_variant_get_child_value(calls->params, 0);
4591- EXPECT_TRUE(check_env(env, "APP_ID", "com.test.multiple_first_1.2.3"));
4592- EXPECT_TRUE(check_env(env, "HELPER_TYPE", "untrusted-type"));
4593- g_variant_unref(env);
4594-
4595- ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
4596+ auto inst2 = helper->launch();
4597+
4598+ auto helperStart2 = systemd->unitCalls();
4599+
4600+ ASSERT_EQ(1u, helperStart2.size());
4601+ EXPECT_EQ(SystemdMock::instanceName(
4602+ {"untrusted-type",
4603+ "com.test.multiple_first_1.2.3",
4604+ std::dynamic_pointer_cast<ubuntu::app_launch::jobs::instance::Base>(inst2)->getInstanceId(),
4605+ 0,
4606+ {}}),
4607+ helperStart2.begin()->name);
4608+
4609+ systemd->managerClear();
4610
4611 /* Let's pass some URLs */
4612 std::vector<ubuntu::app_launch::Helper::URL> urls = {
4613 ubuntu::app_launch::Helper::URL::from_raw("http://ubuntu.com/"),
4614 ubuntu::app_launch::Helper::URL::from_raw("https://ubuntu.com/"),
4615 ubuntu::app_launch::Helper::URL::from_raw("file:///home/phablet/test.txt")};
4616- helper->launch(urls);
4617-
4618- len = 0;
4619- calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
4620- EXPECT_NE(nullptr, calls);
4621- ASSERT_EQ(1u, len);
4622-
4623- env = g_variant_get_child_value(calls->params, 0);
4624- EXPECT_TRUE(check_env(env, "APP_ID", "com.test.multiple_first_1.2.3"));
4625- EXPECT_TRUE(
4626- check_env(env, "APP_URIS", "'http://ubuntu.com/' 'https://ubuntu.com/' 'file:///home/phablet/test.txt'"));
4627- EXPECT_TRUE(check_env(env, "HELPER_TYPE", "untrusted-type"));
4628- EXPECT_FALSE(check_env(env, "INSTANCE_ID", NULL));
4629- g_variant_unref(env);
4630-
4631- ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
4632-
4633- /* Needed as we still haven't ported second-exec.c to use the registry
4634- thread and inherit its cancellable, we need to ensure all the extra
4635- DBus messages error out before ending the test, or otherwise they'll
4636- keep a reference to the DBus bus object. */
4637- pause(100);
4638+
4639+ auto inst3 = helper->launch(urls);
4640+
4641+ auto helperStart3 = systemd->unitCalls();
4642+
4643+ ASSERT_EQ(1u, helperStart3.size());
4644+ EXPECT_EQ(SystemdMock::instanceName(
4645+ {"untrusted-type",
4646+ "com.test.multiple_first_1.2.3",
4647+ std::dynamic_pointer_cast<ubuntu::app_launch::jobs::instance::Base>(inst3)->getInstanceId(),
4648+ 0,
4649+ {}}),
4650+ helperStart3.begin()->name);
4651+
4652+ /* TODO: Check URLS in exec */
4653
4654 return;
4655 }
4656
4657 TEST_F(LibUAL, StopHelper)
4658 {
4659- DbusTestDbusMockObject* obj =
4660- dbus_test_dbus_mock_get_object(mock, "/com/test/untrusted/helper", "com.ubuntu.Upstart0_6.Job", NULL);
4661-
4662 /* Multi helper */
4663 auto untrusted = ubuntu::app_launch::Helper::Type::from_raw("untrusted-type");
4664
4665@@ -1389,33 +845,12 @@
4666
4667 instances[0]->stop();
4668
4669- ASSERT_EQ(dbus_test_dbus_mock_object_check_method_call(mock, obj, "Stop", NULL, NULL), 1);
4670-
4671- guint len = 0;
4672- auto calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Stop", &len, NULL);
4673- EXPECT_NE(nullptr, calls);
4674- ASSERT_EQ(1u, len);
4675-
4676- EXPECT_STREQ("Stop", calls->name);
4677- EXPECT_EQ(2u, g_variant_n_children(calls->params));
4678-
4679- auto block = g_variant_get_child_value(calls->params, 1);
4680- EXPECT_TRUE(g_variant_get_boolean(block));
4681- g_variant_unref(block);
4682-
4683- auto env = g_variant_get_child_value(calls->params, 0);
4684- EXPECT_TRUE(check_env(env, "APP_ID", "com.bar_foo_8432.13.1"));
4685- EXPECT_TRUE(check_env(env, "HELPER_TYPE", "untrusted-type"));
4686- EXPECT_TRUE(check_env(env, "INSTANCE_ID", "24034582324132"));
4687- g_variant_unref(env);
4688-
4689- ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
4690-
4691- /* Needed as we still haven't ported second-exec.c to use the registry
4692- thread and inherit its cancellable, we need to ensure all the extra
4693- DBus messages error out before ending the test, or otherwise they'll
4694- keep a reference to the DBus bus object. */
4695- pause(100);
4696+ auto calls = systemd->stopCalls();
4697+
4698+ ASSERT_EQ(1u, calls.size());
4699+
4700+ EXPECT_EQ(SystemdMock::instanceName({"untrusted-type", "com.bar_foo_8432.13.1", "24034582324132", 0, {}}),
4701+ *calls.begin());
4702
4703 return;
4704 }
4705@@ -1482,23 +917,13 @@
4706 ASSERT_TRUE(ubuntu_app_launch_observer_add_helper_started(helper_observer_cb, "my-type-is-scorpio", &start_data));
4707 ASSERT_TRUE(ubuntu_app_launch_observer_add_helper_stop(helper_observer_cb, "my-type-is-libra", &stop_data));
4708
4709- DbusTestDbusMockObject* obj =
4710- dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);
4711-
4712 /* Basic start */
4713- dbus_test_dbus_mock_object_emit_signal(
4714- mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),
4715- g_variant_new_parsed("('started', ['JOB=untrusted-helper', 'INSTANCE=my-type-is-scorpio::com.foo_foo_1.2.3'])"),
4716- NULL);
4717+ systemd->managerEmitNew(SystemdMock::instanceName({"my-type-is-scorpio", "com.foo_foo_1.2.3", "", 0, {}}), "/");
4718
4719 EXPECT_EVENTUALLY_EQ(1, start_data.count);
4720
4721 /* Basic stop */
4722- dbus_test_dbus_mock_object_emit_signal(
4723- mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),
4724- g_variant_new_parsed(
4725- "('stopped', ['JOB=untrusted-helper', 'INSTANCE=my-type-is-libra:1234:com.bar_bar_44.32'])"),
4726- NULL);
4727+ systemd->managerEmitRemoved(SystemdMock::instanceName({"my-type-is-scorpio", "com.foo_foo_1.2.3", "", 0, {}}), "/");
4728
4729 EXPECT_EVENTUALLY_EQ(1, stop_data.count);
4730
4731@@ -1516,35 +941,20 @@
4732 /* Setup some spew */
4733 SpewMaster spew;
4734
4735- /* Setup the cgroup */
4736- g_setenv("UBUNTU_APP_LAUNCH_CG_MANAGER_NAME", "org.test.cgmock2", TRUE);
4737- DbusTestDbusMock* cgmock2 = dbus_test_dbus_mock_new("org.test.cgmock2");
4738- DbusTestDbusMockObject* cgobject = dbus_test_dbus_mock_get_object(cgmock2, "/org/linuxcontainers/cgmanager",
4739- "org.linuxcontainers.cgmanager0_0", NULL);
4740- gchar* pypids = g_strdup_printf("ret = [%d]", spew.pid());
4741- dbus_test_dbus_mock_object_add_method(cgmock, cgobject, "GetTasksRecursive", G_VARIANT_TYPE("(ss)"),
4742- G_VARIANT_TYPE("ai"), pypids, NULL);
4743- g_free(pypids);
4744-
4745- dbus_test_service_add_task(service, DBUS_TEST_TASK(cgmock2));
4746- dbus_test_task_run(DBUS_TEST_TASK(cgmock2));
4747- g_object_unref(G_OBJECT(cgmock2));
4748-
4749 /* Setup ZG Mock */
4750- DbusTestDbusMock* zgmock = dbus_test_dbus_mock_new("org.gnome.zeitgeist.Engine");
4751- DbusTestDbusMockObject* zgobj =
4752- dbus_test_dbus_mock_get_object(zgmock, "/org/gnome/zeitgeist/log/activity", "org.gnome.zeitgeist.Log", NULL);
4753-
4754- dbus_test_dbus_mock_object_add_method(zgmock, zgobj, "InsertEvents", G_VARIANT_TYPE("a(asaasay)"),
4755- G_VARIANT_TYPE("au"), "ret = [ 0 ]", NULL);
4756-
4757- dbus_test_service_add_task(service, DBUS_TEST_TASK(zgmock));
4758- dbus_test_task_run(DBUS_TEST_TASK(zgmock));
4759- g_object_unref(G_OBJECT(zgmock));
4760+ auto zgmock = std::make_shared<ZeitgeistMock>();
4761+
4762+ /* New Systemd Mock */
4763+ dbus_test_service_remove_task(service, *systemd);
4764+ systemd.reset();
4765+ auto systemd2 = std::make_shared<SystemdMock>(
4766+ std::list<SystemdMock::Instance>{
4767+ {"application-click", "com.test.good_application_1.2.3", {}, spew.pid(), {spew.pid()}}},
4768+ CGROUP_DIR);
4769
4770 /* Give things a chance to start */
4771- EXPECT_EVENTUALLY_FUNC_EQ(DBUS_TEST_TASK_STATE_RUNNING, TASK_STATE(cgmock2));
4772- EXPECT_EVENTUALLY_FUNC_EQ(DBUS_TEST_TASK_STATE_RUNNING, TASK_STATE(zgmock));
4773+ EXPECT_EVENTUALLY_FUNC_EQ(DBUS_TEST_TASK_STATE_RUNNING, systemd2->stateFunc());
4774+ EXPECT_EVENTUALLY_FUNC_EQ(DBUS_TEST_TASK_STATE_RUNNING, zgmock->stateFunc());
4775
4776 /* Setup signal handling */
4777 guint paused_count = 0;
4778@@ -1592,14 +1002,10 @@
4779 EXPECT_EQ(0u, spew.dataCnt());
4780
4781 /* Check to make sure we sent the event to ZG */
4782- guint numcalls = 0;
4783- const DbusTestDbusMockCall* calls =
4784- dbus_test_dbus_mock_object_get_method_calls(zgmock, zgobj, "InsertEvents", &numcalls, NULL);
4785-
4786- EXPECT_NE(nullptr, calls);
4787- EXPECT_EQ(1u, numcalls);
4788-
4789- dbus_test_dbus_mock_object_clear_method_calls(zgmock, zgobj, NULL);
4790+ auto inserts = zgmock->insertCalls();
4791+ EXPECT_EQ(1u, inserts.size());
4792+
4793+ zgmock->clear();
4794
4795 /* Check to ensure we set the OOM score */
4796 EXPECT_EQ("900", spew.oomScore());
4797@@ -1613,11 +1019,10 @@
4798 EXPECT_NE(0u, spew.dataCnt());
4799
4800 /* Check to make sure we sent the event to ZG */
4801- numcalls = 0;
4802- calls = dbus_test_dbus_mock_object_get_method_calls(zgmock, zgobj, "InsertEvents", &numcalls, NULL);
4803+ auto inserts2 = zgmock->insertCalls();
4804+ EXPECT_EQ(1u, inserts2.size());
4805
4806- EXPECT_NE(nullptr, calls);
4807- EXPECT_EQ(1u, numcalls);
4808+ zgmock->clear();
4809
4810 /* Check to ensure we set the OOM score */
4811 EXPECT_EQ("100", spew.oomScore());
4812@@ -1632,41 +1037,22 @@
4813 /* Setup A TON OF spew */
4814 std::array<SpewMaster, 50> spews;
4815
4816- /* Setup the cgroup */
4817- g_setenv("UBUNTU_APP_LAUNCH_CG_MANAGER_NAME", "org.test.cgmock2", TRUE);
4818- DbusTestDbusMock* cgmock2 = dbus_test_dbus_mock_new("org.test.cgmock2");
4819- DbusTestDbusMockObject* cgobject = dbus_test_dbus_mock_get_object(cgmock2, "/org/linuxcontainers/cgmanager",
4820- "org.linuxcontainers.cgmanager0_0", NULL);
4821-
4822- std::string pypids = "ret = [ " + std::accumulate(spews.begin(), spews.end(), std::string{},
4823- [](const std::string& accum, SpewMaster& spew) {
4824- return accum.empty() ?
4825- std::to_string(spew.pid()) :
4826- accum + ", " + std::to_string(spew.pid());
4827- }) +
4828- "]";
4829- dbus_test_dbus_mock_object_add_method(cgmock, cgobject, "GetTasksRecursive", G_VARIANT_TYPE("(ss)"),
4830- G_VARIANT_TYPE("ai"), pypids.c_str(), NULL);
4831-
4832- dbus_test_service_add_task(service, DBUS_TEST_TASK(cgmock2));
4833- dbus_test_task_run(DBUS_TEST_TASK(cgmock2));
4834- g_object_unref(G_OBJECT(cgmock2));
4835-
4836 /* Setup ZG Mock */
4837- DbusTestDbusMock* zgmock = dbus_test_dbus_mock_new("org.gnome.zeitgeist.Engine");
4838- DbusTestDbusMockObject* zgobj =
4839- dbus_test_dbus_mock_get_object(zgmock, "/org/gnome/zeitgeist/log/activity", "org.gnome.zeitgeist.Log", NULL);
4840-
4841- dbus_test_dbus_mock_object_add_method(zgmock, zgobj, "InsertEvents", G_VARIANT_TYPE("a(asaasay)"),
4842- G_VARIANT_TYPE("au"), "ret = [ 0 ]", NULL);
4843-
4844- dbus_test_service_add_task(service, DBUS_TEST_TASK(zgmock));
4845- dbus_test_task_run(DBUS_TEST_TASK(zgmock));
4846- g_object_unref(G_OBJECT(zgmock));
4847+ auto zgmock = std::make_shared<ZeitgeistMock>();
4848+
4849+ /* New Systemd Mock */
4850+ dbus_test_service_remove_task(service, *systemd);
4851+ systemd.reset();
4852+ std::vector<pid_t> spewpids;
4853+ std::transform(spews.begin(), spews.end(), spewpids.begin(), [](SpewMaster& spew) { return spew.pid(); });
4854+ auto systemd2 = std::make_shared<SystemdMock>(
4855+ std::list<SystemdMock::Instance>{
4856+ {"application-click", "com.test.good_application_1.2.3", {}, spews.begin()->pid(), spewpids}},
4857+ CGROUP_DIR);
4858
4859 /* Give things a chance to start */
4860- EXPECT_EVENTUALLY_FUNC_EQ(DBUS_TEST_TASK_STATE_RUNNING, TASK_STATE(cgmock2));
4861- EXPECT_EVENTUALLY_FUNC_EQ(DBUS_TEST_TASK_STATE_RUNNING, TASK_STATE(zgmock));
4862+ EXPECT_EVENTUALLY_FUNC_EQ(DBUS_TEST_TASK_STATE_RUNNING, systemd2->stateFunc());
4863+ EXPECT_EVENTUALLY_FUNC_EQ(DBUS_TEST_TASK_STATE_RUNNING, zgmock->stateFunc());
4864
4865 /* Setup signal handling */
4866 guint paused_count = 0;
4867@@ -1763,23 +1149,6 @@
4868 g_free(procdir);
4869 ASSERT_TRUE(g_file_set_contents(oomadjfile, "0", -1, NULL));
4870
4871- /* Setup the cgroup */
4872- g_setenv("UBUNTU_APP_LAUNCH_CG_MANAGER_NAME", "org.test.cgmock2", TRUE);
4873- DbusTestDbusMock* cgmock2 = dbus_test_dbus_mock_new("org.test.cgmock2");
4874- DbusTestDbusMockObject* cgobject = dbus_test_dbus_mock_get_object(cgmock2, "/org/linuxcontainers/cgmanager",
4875- "org.linuxcontainers.cgmanager0_0", NULL);
4876- gchar* pypids = g_strdup_printf("ret = [%d]", testpid);
4877- dbus_test_dbus_mock_object_add_method(cgmock, cgobject, "GetTasksRecursive", G_VARIANT_TYPE("(ss)"),
4878- G_VARIANT_TYPE("ai"), pypids, NULL);
4879- g_free(pypids);
4880-
4881- dbus_test_service_add_task(service, DBUS_TEST_TASK(cgmock2));
4882- dbus_test_task_run(DBUS_TEST_TASK(cgmock2));
4883- g_object_unref(G_OBJECT(cgmock2));
4884-
4885- /* Give things a chance to start */
4886- EXPECT_EVENTUALLY_FUNC_EQ(DBUS_TEST_TASK_STATE_RUNNING, TASK_STATE(cgmock2));
4887-
4888 /* Get our app object */
4889 auto appid = ubuntu::app_launch::AppID::find(registry, "com.test.good_application_1.2.3");
4890 auto app = ubuntu::app_launch::Application::create(appid, registry);
4891@@ -1833,8 +1202,6 @@
4892
4893 TEST_F(LibUAL, StartSessionHelper)
4894 {
4895- DbusTestDbusMockObject* obj =
4896- dbus_test_dbus_mock_get_object(mock, "/com/test/untrusted/helper", "com.ubuntu.Upstart0_6.Job", NULL);
4897 MirConnection* conn = mir_connect_sync("libual-test", "start-session-helper"); // Mocked, doesn't need cleaning up
4898 MirPromptSession* msession = mir_connection_create_prompt_session_sync(conn, 5, nullptr, nullptr);
4899
4900@@ -1851,42 +1218,23 @@
4901
4902 helper->launch(msession);
4903
4904- guint len = 0;
4905- const DbusTestDbusMockCall* calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
4906- EXPECT_NE(nullptr, calls);
4907- ASSERT_EQ(1u, len);
4908-
4909- EXPECT_STREQ("Start", calls->name);
4910- EXPECT_EQ(2u, g_variant_n_children(calls->params));
4911-
4912- GVariant* block = g_variant_get_child_value(calls->params, 1);
4913- EXPECT_TRUE(g_variant_get_boolean(block));
4914- g_variant_unref(block);
4915+ auto calls = systemd->unitCalls();
4916+ ASSERT_EQ(1u, calls.size());
4917
4918 /* Check the environment */
4919- GVariant* env = g_variant_get_child_value(calls->params, 0);
4920+ auto& env = calls.begin()->environment;
4921 EXPECT_TRUE(check_env(env, "APP_ID", "com.test.multiple_first_1.2.3"));
4922 EXPECT_TRUE(check_env(env, "HELPER_TYPE", "untrusted-type"));
4923
4924- GVariant* mnamev = find_env(env, "UBUNTU_APP_LAUNCH_DEMANGLE_NAME");
4925- ASSERT_NE(nullptr, mnamev); /* Have to assert because, eh, GVariant */
4926- EXPECT_STREQ(g_dbus_connection_get_unique_name(bus),
4927- g_variant_get_string(mnamev, nullptr) + strlen("UBUNTU_APP_LAUNCH_DEMANGLE_NAME="));
4928- GVariant* mpathv = find_env(env, "UBUNTU_APP_LAUNCH_DEMANGLE_PATH");
4929- ASSERT_NE(nullptr, mpathv); /* Have to assert because, eh, GVariant */
4930-
4931- g_variant_unref(env);
4932+ auto demanglename = find_env(env, "UBUNTU_APP_LAUNCH_DEMANGLE_NAME");
4933+ ASSERT_FALSE(demanglename.empty());
4934+ EXPECT_EQ(g_dbus_connection_get_unique_name(bus), split_env(demanglename).second);
4935+ auto demanglepath = find_env(env, "UBUNTU_APP_LAUNCH_DEMANGLE_PATH");
4936+ ASSERT_FALSE(demanglepath.empty());
4937
4938 /* Setup environment for call */
4939- const gchar* mname = g_variant_get_string(mnamev, nullptr);
4940- mname += strlen("UBUNTU_APP_LAUNCH_DEMANGLE_NAME=");
4941- g_setenv("UBUNTU_APP_LAUNCH_DEMANGLE_NAME", mname, TRUE);
4942- g_variant_unref(mnamev);
4943-
4944- const gchar* mpath = g_variant_get_string(mpathv, nullptr);
4945- mpath += strlen("UBUNTU_APP_LAUNCH_DEMANGLE_PATH=");
4946- g_setenv("UBUNTU_APP_LAUNCH_DEMANGLE_PATH", mpath, TRUE);
4947- g_variant_unref(mpathv);
4948+ g_setenv("UBUNTU_APP_LAUNCH_DEMANGLE_NAME", split_env(demanglename).second.c_str(), TRUE);
4949+ g_setenv("UBUNTU_APP_LAUNCH_DEMANGLE_PATH", split_env(demanglepath).second.c_str(), TRUE);
4950
4951 /* Exec our tool */
4952 std::promise<std::string> outputpromise;
4953@@ -1919,11 +1267,11 @@
4954
4955 ASSERT_STREQ(filedata, outputfuture.get().c_str());
4956
4957- ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
4958-
4959 return;
4960 }
4961
4962+#if 0
4963+/* Need to change as helpers change to not use Upstart features */
4964 TEST_F(LibUAL, SetExec)
4965 {
4966 DbusTestDbusMockObject* obj =
4967@@ -1978,6 +1326,7 @@
4968
4969 ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
4970 }
4971+#endif
4972
4973 TEST_F(LibUAL, AppInfo)
4974 {
4975
4976=== modified file 'tests/systemd-mock.h'
4977--- tests/systemd-mock.h 2017-02-04 03:53:34 +0000
4978+++ tests/systemd-mock.h 2017-03-21 03:20:55 +0000
4979@@ -551,4 +551,9 @@
4980 throw std::runtime_error{"Mock disfunctional"};
4981 }
4982 }
4983+
4984+ std::function<DbusTestTaskState()> stateFunc()
4985+ {
4986+ return [this] { return dbus_test_task_get_state(DBUS_TEST_TASK(mock)); };
4987+ }
4988 };
4989
4990=== added file 'tests/zg-mock.h'
4991--- tests/zg-mock.h 1970-01-01 00:00:00 +0000
4992+++ tests/zg-mock.h 2017-03-21 03:20:55 +0000
4993@@ -0,0 +1,117 @@
4994+/*
4995+ * Copyright © 2017 Canonical Ltd.
4996+ *
4997+ * This program is free software; you can redistribute it and/or modify
4998+ * it under the terms of the GNU General Public License as published by
4999+ * the Free Software Foundation; version 3.
5000+ *
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches