Merge lp:~ted/url-dispatcher/de-upstart into lp:url-dispatcher

Proposed by Ted Gould
Status: Merged
Approved by: dobey
Approved revision: 114
Merged at revision: 115
Proposed branch: lp:~ted/url-dispatcher/de-upstart
Merge into: lp:url-dispatcher
Diff against target: 783 lines (+606/-72)
4 files modified
tests/CMakeLists.txt (+1/-1)
tests/service-test.cc (+28/-71)
tests/systemd-mock.h (+576/-0)
tests/xdg-data/applications/foo-bar.desktop (+1/-0)
To merge this branch: bzr merge lp:~ted/url-dispatcher/de-upstart
Reviewer Review Type Date Requested Status
dobey (community) Approve
unity-api-1-bot continuous-integration Needs Fixing
Review via email: mp+320123@code.launchpad.net

Commit message

Remove Upstart from the test suite and replace it with systemd

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
dobey (dobey) wrote :

21:59:22 /<<BUILDDIR>>/url-dispatcher-0.1+17.04.20170314+fetch1805bzr114/tests/dispatcher-test.cc:329:2: required from here
21:59:22 /<<BUILDDIR>>/url-dispatcher-0.1+17.04.20170314+fetch1805bzr114/tests/dispatcher-test.cc:331:2: required from here
21:59:22 /<<BUILDDIR>>/url-dispatcher-0.1+17.04.20170314+fetch1805bzr114/tests/dispatcher-test.cc:343:2: required from here

21:59:25 /<<BUILDDIR>>/url-dispatcher-0.1+17.04.20170314+fetch1805bzr114/tests/lib-test.cc:98:2: required from here
21:59:25 /<<BUILDDIR>>/url-dispatcher-0.1+17.04.20170314+fetch1805bzr114/tests/lib-test.cc:148:2: required from here

21:58:57 /<<BUILDDIR>>/url-dispatcher-0.1+17.04.20170314+fetch1805bzr114/tests/url-db-test.cc:169:2: required from here

21:59:15 /<<BUILDDIR>>/url-dispatcher-0.1+17.04.20170314+fetch1805bzr114/tests/exec-tool-test.cc:106:2: required from here

21:59:22 /usr/src/googletest/googletest/include/gtest/gtest.h:1392:11: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]

review: Needs Fixing
Revision history for this message
dobey (dobey) wrote :

Never mind about the signed compares. They aren't from this branch, and seem to already exist in the last build.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'tests/CMakeLists.txt'
2--- tests/CMakeLists.txt 2017-03-14 14:31:35 +0000
3+++ tests/CMakeLists.txt 2017-03-16 21:55:16 +0000
4@@ -73,7 +73,7 @@
5 # service test
6 ###########################
7
8-add_executable (service-test service-test.cc)
9+add_executable (service-test service-test.cc ${CMAKE_SOURCE_DIR}/service/glib-thread.cpp)
10 target_link_libraries (service-test
11 url-db-lib
12 dispatcher
13
14=== modified file 'tests/service-test.cc'
15--- tests/service-test.cc 2015-06-26 13:27:22 +0000
16+++ tests/service-test.cc 2017-03-16 21:55:16 +0000
17@@ -23,20 +23,24 @@
18 #include <libdbustest/dbus-test.h>
19
20 #include "url-db.h"
21+#include "systemd-mock.h"
22+
23+#define CGROUP_DIR (CMAKE_BINARY_DIR "/systemd-service-test-cgroups")
24
25 class ServiceTest : public ::testing::Test
26 {
27 protected:
28 DbusTestService * service = nullptr;
29- DbusTestDbusMock * mock = nullptr;
30 DbusTestDbusMock * dashmock = nullptr;
31- DbusTestDbusMockObject * obj = nullptr;
32- DbusTestDbusMockObject * jobobj = nullptr;
33 DbusTestProcess * dispatcher = nullptr;
34+ std::shared_ptr<SystemdMock> systemd;
35 GDBusConnection * bus = nullptr;
36
37 virtual void SetUp() {
38 g_setenv("UBUNTU_APP_LAUNCH_USE_SESSION", "1", TRUE);
39+ g_setenv("UBUNTU_APP_LAUNCH_SYSTEMD_CGROUP_ROOT", CGROUP_DIR, TRUE);
40+ g_setenv("UBUNTU_APP_LAUNCH_SYSTEMD_PATH", "/this/should/not/exist", TRUE);
41+
42 g_setenv("URL_DISPATCHER_DISABLE_RECOVERABLE_ERROR", "1", TRUE);
43 g_setenv("URL_DISPATCHER_DISABLE_SCOPE_CHECKING", "1", TRUE);
44 g_setenv("XDG_DATA_DIRS", XDG_DATA_DIRS, TRUE);
45@@ -50,28 +54,12 @@
46 dbus_test_task_set_name(DBUS_TEST_TASK(dispatcher), "Dispatcher");
47 dbus_test_service_add_task(service, DBUS_TEST_TASK(dispatcher));
48
49- /* Upstart Mock */
50- mock = dbus_test_dbus_mock_new("com.ubuntu.Upstart");
51- obj = dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", nullptr);
52-
53- dbus_test_dbus_mock_object_add_method(mock, obj,
54- "GetJobByName",
55- G_VARIANT_TYPE_STRING,
56- G_VARIANT_TYPE_OBJECT_PATH, /* out */
57- "ret = dbus.ObjectPath('/job')", /* python */
58- nullptr); /* error */
59-
60- jobobj = dbus_test_dbus_mock_get_object(mock, "/job", "com.ubuntu.Upstart0_6.Job", nullptr);
61-
62- dbus_test_dbus_mock_object_add_method(mock, jobobj,
63- "Start",
64- G_VARIANT_TYPE("(asb)"),
65- G_VARIANT_TYPE_OBJECT_PATH, /* out */
66- "ret = dbus.ObjectPath('/instance')", /* python */
67- nullptr); /* error */
68-
69- dbus_test_task_set_name(DBUS_TEST_TASK(mock), "Upstart");
70- dbus_test_service_add_task(service, DBUS_TEST_TASK(mock));
71+ /* Systemd Mock */
72+ systemd = std::make_shared<SystemdMock>(
73+ std::list<SystemdMock::Instance>{
74+ {"application-legacy", "single", {}, getpid(), {getpid()}},
75+ }, CGROUP_DIR);
76+ dbus_test_service_add_task(service, *systemd);
77
78 /* Dash Mock */
79 dashmock = dbus_test_dbus_mock_new("com.canonical.UnityDash");
80@@ -96,12 +84,10 @@
81 }
82
83 virtual void TearDown() {
84- gchar * cmdline = g_strdup_printf("kill -TERM %d", dbus_test_process_get_pid(dispatcher));
85- g_spawn_command_line_sync(cmdline, nullptr, nullptr, nullptr, nullptr);
86- g_free(cmdline);
87+ kill(dbus_test_process_get_pid(dispatcher), SIGTERM);
88
89+ systemd.reset();
90 g_clear_object(&dispatcher);
91- g_clear_object(&mock);
92 g_clear_object(&dashmock);
93 g_clear_object(&service);
94
95@@ -165,10 +151,8 @@
96 g_main_loop_run(main);
97 g_main_loop_unref(main);
98
99- guint callslen = 0;
100- dbus_test_dbus_mock_object_get_method_calls(mock, jobobj, "Start", &callslen, nullptr);
101-
102- ASSERT_EQ(callslen, 0);
103+ auto calls = systemd->unitCalls();
104+ ASSERT_EQ(0u, calls.size());
105 }
106
107 TEST_F(ServiceTest, ApplicationTest) {
108@@ -181,30 +165,10 @@
109 g_main_loop_run(main);
110 g_main_loop_unref(main);
111
112- guint callslen = 0;
113- const DbusTestDbusMockCall * calls = dbus_test_dbus_mock_object_get_method_calls(mock, jobobj, "Start", &callslen, nullptr);
114-
115- ASSERT_EQ(callslen, 1);
116-
117- /* Making sure the APP_ID is here. We're not testing more to
118- make it so the tests break less, that should be tested in
119- Upstart App Launch, we don't need to retest */
120- GVariant * env = g_variant_get_child_value(calls->params, 0);
121- GVariantIter iter;
122- bool found_appid = false;
123- g_variant_iter_init(&iter, env);
124- gchar * var = nullptr;
125-
126- while (g_variant_iter_loop(&iter, "s", &var)) {
127- if (g_strcmp0(var, "APP_ID=foo-bar") == 0) {
128- ASSERT_FALSE(found_appid);
129- found_appid = true;
130- }
131- }
132-
133- g_variant_unref(env);
134-
135- ASSERT_TRUE(found_appid);
136+ /* Check to see it called systemd */
137+ auto calls = systemd->unitCalls();
138+ ASSERT_EQ(1u, calls.size());
139+ EXPECT_EQ(SystemdMock::instanceName({"application-legacy", "foo-bar", "", 0, {}}), calls.begin()->name);
140 }
141
142 TEST_F(ServiceTest, TestURLTest) {
143@@ -215,7 +179,7 @@
144 };
145
146 gchar ** appids = url_dispatch_url_appid(testurls);
147- ASSERT_EQ(1, g_strv_length(appids));
148+ ASSERT_EQ(1u, g_strv_length(appids));
149
150 EXPECT_STREQ("foo-bar", appids[0]);
151
152@@ -229,7 +193,7 @@
153 };
154
155 gchar ** multiappids = url_dispatch_url_appid(multiurls);
156- ASSERT_EQ(2, g_strv_length(multiappids));
157+ ASSERT_EQ(2u, g_strv_length(multiappids));
158
159 EXPECT_STREQ("bar-foo", multiappids[0]);
160 EXPECT_STREQ("foo-bar", multiappids[1]);
161@@ -243,7 +207,7 @@
162 };
163
164 gchar ** errorappids = url_dispatch_url_appid(errorurls);
165- ASSERT_EQ(0, g_strv_length(errorappids));
166+ ASSERT_EQ(0u, g_strv_length(errorappids));
167
168 g_strfreev(errorappids);
169 }
170@@ -283,19 +247,12 @@
171 g_main_loop_unref(main);
172
173 guint callslen = 0;
174- const DbusTestDbusMockCall * calls = nullptr;
175- calls = dbus_test_dbus_mock_object_get_method_calls(mock, jobobj, "Start", &callslen, nullptr);
176-
177- EXPECT_NE(calls, nullptr);
178- EXPECT_EQ(0, callslen);
179-
180- callslen = 0;
181- calls = dbus_test_dbus_mock_object_get_method_calls(dashmock, fdoobj, "Open", &callslen, nullptr);
182-
183- EXPECT_EQ(1, callslen);
184+ auto calls = dbus_test_dbus_mock_object_get_method_calls(dashmock, fdoobj, "Open", &callslen, nullptr);
185+
186+ EXPECT_EQ(1u, callslen);
187 EXPECT_TRUE(g_variant_equal(calls[0].params, g_variant_new_parsed("(['scopeish://foo-bar'], @a{sv} {})")));
188
189- EXPECT_EQ(1, focus_count);
190+ EXPECT_EQ(1u, focus_count);
191
192 g_dbus_connection_signal_unsubscribe(bus, focus_signal);
193 g_clear_object(&bus);
194
195=== added file 'tests/systemd-mock.h'
196--- tests/systemd-mock.h 1970-01-01 00:00:00 +0000
197+++ tests/systemd-mock.h 2017-03-16 21:55:16 +0000
198@@ -0,0 +1,576 @@
199+/*
200+ * Copyright © 2017 Canonical Ltd.
201+ *
202+ * This program is free software; you can redistribute it and/or modify
203+ * it under the terms of the GNU General Public License as published by
204+ * the Free Software Foundation; version 3.
205+ *
206+ * This program is distributed in the hope that it will be useful,
207+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
208+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
209+ * GNU General Public License for more details.
210+ *
211+ * You should have received a copy of the GNU General Public License
212+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
213+ *
214+ * Authors:
215+ * Ted Gould <ted@canonical.com>
216+ */
217+
218+#include <algorithm>
219+#include <future>
220+#include <list>
221+#include <map>
222+#include <memory>
223+#include <numeric>
224+#include <type_traits>
225+
226+#include <gio/gio.h>
227+
228+#include <libdbustest/dbus-test.h>
229+
230+#include "glib-thread.h"
231+
232+class SystemdMock
233+{
234+public:
235+ struct Instance
236+ {
237+ std::string job;
238+ std::string appid;
239+ std::string instanceid;
240+ pid_t primaryPid;
241+ std::vector<pid_t> pids;
242+ };
243+
244+private:
245+ DbusTestDbusMock* mock = nullptr;
246+ DbusTestDbusMockObject* managerobj = nullptr;
247+ GLib::ContextThread thread;
248+ std::list<std::pair<Instance, DbusTestDbusMockObject*>> insts;
249+
250+ void throwError(GError* error)
251+ {
252+ if (error == nullptr)
253+ {
254+ return;
255+ }
256+
257+ auto message = std::string{"Error in systemd mock: "} + error->message;
258+ g_error_free(error);
259+ throw std::runtime_error{message};
260+ }
261+
262+public:
263+ SystemdMock(const std::list<Instance>& instances, const std::string& controlGroupPath)
264+ {
265+ GError* error = nullptr;
266+ mock = dbus_test_dbus_mock_new("org.freedesktop.systemd1");
267+ dbus_test_task_set_bus(DBUS_TEST_TASK(mock), DBUS_TEST_SERVICE_BUS_SESSION);
268+ dbus_test_task_set_name(DBUS_TEST_TASK(mock), "systemd");
269+
270+ managerobj = dbus_test_dbus_mock_get_object(mock, "/org/freedesktop/systemd1",
271+ "org.freedesktop.systemd1.Manager", nullptr);
272+
273+ dbus_test_dbus_mock_object_add_method(mock, managerobj, "Subscribe", nullptr, nullptr, "", nullptr);
274+ dbus_test_dbus_mock_object_add_method(
275+ mock, managerobj, "ListUnits", nullptr, G_VARIANT_TYPE("(a(ssssssouso))"), /* ret type */
276+ ("ret = [ " + std::accumulate(instances.begin(), instances.end(), std::string{},
277+ [](const std::string accum, const Instance& inst) {
278+ std::string retval = accum;
279+
280+ if (!retval.empty())
281+ {
282+ retval += ", ";
283+ }
284+
285+ retval += std::string{"("} + /* start tuple */
286+ "'" + instanceName(inst) + "', " + /* id */
287+ "'unused', " + /* description */
288+ "'unused', " + /* load state */
289+ "'unused', " + /* active state */
290+ "'unused', " + /* substate */
291+ "'unused', " + /* following */
292+ "'/unused', " + /* path */
293+ "5, " + /* jobId */
294+ "'unused', " + /* jobType */
295+ "'" + instancePath(inst) + "'" + /* jobPath */
296+ ")"; /* finish tuple */
297+
298+ return retval;
299+ }) +
300+ "]")
301+ .c_str(),
302+ &error);
303+ throwError(error);
304+
305+ dbus_test_dbus_mock_object_add_method(
306+ mock, managerobj, "GetUnit", G_VARIANT_TYPE_STRING, G_VARIANT_TYPE_OBJECT_PATH, /* ret type */
307+ ("ret = '/'\n" + std::accumulate(instances.begin(), instances.end(), std::string{},
308+ [](const std::string accum, const Instance& inst) {
309+ std::string retval = accum;
310+
311+ retval += "if args[0] == '" + instanceName(inst) + "':\n";
312+ retval += "\tret = '" + instancePath(inst) + "'\n";
313+
314+ return retval;
315+ }))
316+ .c_str(),
317+ &error);
318+ throwError(error);
319+
320+ dbus_test_dbus_mock_object_add_method(
321+ mock, managerobj, "StopUnit", G_VARIANT_TYPE("(ss)"), G_VARIANT_TYPE_OBJECT_PATH, /* ret type */
322+ std::accumulate(instances.begin(), instances.end(), std::string{},
323+ [](const std::string accum, const Instance& inst) {
324+ std::string retval = accum;
325+
326+ retval += "if args[0] == '" + instanceName(inst) + "':\n";
327+ retval += "\tret = '" + instancePath(inst) + "'\n";
328+
329+ return retval;
330+ })
331+ .c_str(),
332+ &error);
333+ throwError(error);
334+
335+ dbus_test_dbus_mock_object_add_method(
336+ mock, managerobj, "StartTransientUnit", G_VARIANT_TYPE("(ssa(sv)a(sa(sv)))"),
337+ G_VARIANT_TYPE_OBJECT_PATH, /* ret type */
338+ std::accumulate(instances.begin(), instances.end(), std::string{"ret = '/'\n"},
339+ [](const std::string accum, const Instance& inst) {
340+ std::string retval = accum;
341+
342+ retval += "if args[0] == '" + instanceName(inst) + "':\n";
343+ retval += "\traise dbus.exceptions.DBusException('Already running app" +
344+ instanceName(inst) + "', name='org.freedesktop.systemd1.UnitExists')\n";
345+
346+ return retval;
347+ })
348+ .c_str(),
349+ &error);
350+ throwError(error);
351+
352+ dbus_test_dbus_mock_object_add_method(mock, managerobj, "ResetFailedUnit", G_VARIANT_TYPE_STRING,
353+ nullptr, /* ret type */
354+ "", &error);
355+ throwError(error);
356+
357+ for (auto& instance : instances)
358+ {
359+ auto obj = dbus_test_dbus_mock_get_object(mock, instancePath(instance).c_str(),
360+ "org.freedesktop.systemd1.Service", &error);
361+ throwError(error);
362+ dbus_test_dbus_mock_object_add_property(mock, obj, "MainPID", G_VARIANT_TYPE_UINT32,
363+ g_variant_new_uint32(instance.primaryPid), &error);
364+ throwError(error);
365+ dbus_test_dbus_mock_object_add_property(mock, obj, "Result", G_VARIANT_TYPE_STRING,
366+ g_variant_new_string("success"), &error);
367+ throwError(error);
368+
369+ /* Control Group */
370+ auto dir = g_build_filename(controlGroupPath.c_str(), instancePath(instance).c_str(), nullptr);
371+ auto tasks = g_build_filename(dir, "tasks", nullptr);
372+
373+ g_mkdir_with_parents(dir, 0777);
374+
375+ g_file_set_contents(tasks,
376+ std::accumulate(instance.pids.begin(), instance.pids.end(), std::string{},
377+ [](const std::string& accum, pid_t pid) {
378+ if (accum.empty())
379+ {
380+ return std::to_string(pid);
381+ }
382+ else
383+ {
384+ return accum + "\n" + std::to_string(pid);
385+ }
386+ })
387+ .c_str(),
388+ -1, &error);
389+ throwError(error);
390+
391+ g_free(tasks);
392+ g_free(dir);
393+
394+ dbus_test_dbus_mock_object_add_property(mock, obj, "ControlGroup", G_VARIANT_TYPE_STRING,
395+ g_variant_new_string(instancePath(instance).c_str()), nullptr);
396+
397+ insts.emplace_back(std::make_pair(instance, obj));
398+ }
399+ }
400+
401+ ~SystemdMock()
402+ {
403+ g_debug("Destroying the Systemd Mock");
404+ g_clear_object(&mock);
405+ }
406+
407+ static std::string dbusSafe(const std::string& input)
408+ {
409+ std::string output = input;
410+ std::transform(output.begin(), output.end(), output.begin(), [](char in) {
411+ if (std::isalpha(in) || std::isdigit(in))
412+ {
413+ return in;
414+ }
415+ else
416+ {
417+ return '_';
418+ }
419+
420+ });
421+ return output;
422+ }
423+
424+ static std::string instancePath(const Instance& inst)
425+ {
426+ std::string retval = std::string{"/"} + dbusSafe(inst.job) + "/" + dbusSafe(inst.appid);
427+
428+ if (!inst.instanceid.empty())
429+ {
430+ retval += "/" + dbusSafe(inst.instanceid);
431+ }
432+
433+ return retval;
434+ }
435+
436+ static std::string instanceName(const Instance& inst)
437+ {
438+ return std::string{"ubuntu-app-launch--"} + inst.job + "--" + inst.appid + "--" + inst.instanceid + ".service";
439+ }
440+
441+ operator std::shared_ptr<DbusTestTask>()
442+ {
443+ std::shared_ptr<DbusTestTask> retval(DBUS_TEST_TASK(g_object_ref(mock)),
444+ [](DbusTestTask* task) { g_clear_object(&task); });
445+ return retval;
446+ }
447+
448+ operator DbusTestTask*()
449+ {
450+ return DBUS_TEST_TASK(mock);
451+ }
452+
453+ operator DbusTestProcess*()
454+ {
455+ return DBUS_TEST_PROCESS(mock);
456+ }
457+
458+ operator DbusTestDbusMock*()
459+ {
460+ return mock;
461+ }
462+
463+ unsigned int subscribeCallsCnt()
464+ {
465+ guint len = 0;
466+ GError* error = nullptr;
467+
468+ dbus_test_dbus_mock_object_get_method_calls(mock, /* mock */
469+ managerobj, /* manager */
470+ "Subscribe", /* function */
471+ &len, /* number */
472+ &error /* error */
473+ );
474+
475+ if (error != nullptr)
476+ {
477+ g_warning("Unable to get 'Subscribe' calls from systemd mock: %s", error->message);
478+ g_error_free(error);
479+ throw std::runtime_error{"Mock disfunctional"};
480+ }
481+
482+ return len;
483+ }
484+
485+ unsigned int listCallsCnt()
486+ {
487+ guint len = 0;
488+ GError* error = nullptr;
489+
490+ dbus_test_dbus_mock_object_get_method_calls(mock, /* mock */
491+ managerobj, /* manager */
492+ "ListUnits", /* function */
493+ &len, /* number */
494+ &error /* error */
495+ );
496+
497+ if (error != nullptr)
498+ {
499+ g_warning("Unable to get 'Subscribe' calls from systemd mock: %s", error->message);
500+ g_error_free(error);
501+ throw std::runtime_error{"Mock disfunctional"};
502+ }
503+
504+ return len;
505+ }
506+
507+ std::list<std::string> stopCalls()
508+ {
509+ guint len = 0;
510+ GError* error = nullptr;
511+
512+ auto calls = dbus_test_dbus_mock_object_get_method_calls(mock, /* mock */
513+ managerobj, /* manager */
514+ "StopUnit", /* function */
515+ &len, /* number */
516+ &error /* error */
517+ );
518+
519+ if (error != nullptr)
520+ {
521+ g_warning("Unable to get 'StopUnit' calls from systemd mock: %s", error->message);
522+ g_error_free(error);
523+ throw std::runtime_error{"Mock disfunctional"};
524+ }
525+
526+ std::list<std::string> retval;
527+
528+ for (unsigned int i = 0; i < len; i++)
529+ {
530+ auto& call = calls[i];
531+ gchar* name = nullptr;
532+ gchar* inst = nullptr;
533+
534+ g_variant_get(call.params, "(&s&s)", &name, &inst);
535+
536+ if (name == nullptr)
537+ {
538+ g_warning("Invalid 'name' on 'StopUnit' call");
539+ continue;
540+ }
541+
542+ retval.emplace_back(name);
543+ }
544+
545+ return retval;
546+ }
547+
548+ struct TransientUnit
549+ {
550+ std::string name;
551+ std::set<std::string> environment;
552+ std::string execpath;
553+ std::list<std::string> execline;
554+ };
555+
556+ std::list<TransientUnit> unitCalls()
557+ {
558+ guint len = 0;
559+ GError* error = nullptr;
560+
561+ auto calls = dbus_test_dbus_mock_object_get_method_calls(mock, /* mock */
562+ managerobj, /* manager */
563+ "StartTransientUnit", /* function */
564+ &len, /* number */
565+ &error /* error */
566+ );
567+
568+ if (error != nullptr)
569+ {
570+ g_warning("Unable to get 'StartTransientUnit' calls from systemd mock: %s", error->message);
571+ g_error_free(error);
572+ throw std::runtime_error{"Mock disfunctional"};
573+ }
574+
575+ std::list<TransientUnit> retval;
576+
577+ for (unsigned int i = 0; i < len; i++)
578+ {
579+ auto& call = calls[i];
580+ gchar* name = nullptr;
581+
582+ g_variant_get_child(call.params, 0, "&s", &name);
583+
584+ if (name == nullptr)
585+ {
586+ g_warning("Invalid 'name' on 'StartTransientUnit' call");
587+ continue;
588+ }
589+
590+ TransientUnit unit;
591+ unit.name = name;
592+
593+ auto paramarray = g_variant_get_child_value(call.params, 2);
594+ gchar* ckey;
595+ GVariant* var;
596+ GVariantIter iter;
597+ g_variant_iter_init(&iter, paramarray);
598+ while (g_variant_iter_loop(&iter, "(sv)", &ckey, &var))
599+ {
600+ g_debug("Looking at parameter: %s", ckey);
601+ std::string key{ckey};
602+
603+ if (key == "Environment")
604+ {
605+ GVariantIter array;
606+ gchar* envvar;
607+ g_variant_iter_init(&array, var);
608+
609+ while (g_variant_iter_loop(&array, "&s", &envvar))
610+ {
611+ unit.environment.emplace(envvar);
612+ }
613+ }
614+ else if (key == "ExecStart")
615+ {
616+ /* a(sasb) */
617+ if (g_variant_n_children(var) > 1)
618+ {
619+ g_warning("'ExecStart' has more than one entry, only processing the first");
620+ }
621+
622+ auto tuple = g_variant_get_child_value(var, 0);
623+
624+ const gchar* cpath = nullptr;
625+ g_variant_get_child(tuple, 0, "&s", &cpath);
626+
627+ if (cpath != nullptr)
628+ {
629+ unit.execpath = cpath;
630+ }
631+ else
632+ {
633+ g_warning("'ExecStart[0][0]' isn't a string?");
634+ }
635+
636+ auto vexecarray = g_variant_get_child_value(tuple, 1);
637+ GVariantIter execarray;
638+ g_variant_iter_init(&execarray, vexecarray);
639+ const gchar* execentry;
640+
641+ while (g_variant_iter_loop(&execarray, "&s", &execentry))
642+ {
643+ unit.execline.emplace_back(execentry);
644+ }
645+
646+ g_clear_pointer(&vexecarray, g_variant_unref);
647+ g_clear_pointer(&tuple, g_variant_unref);
648+ }
649+ }
650+ g_variant_unref(paramarray);
651+
652+ retval.emplace_back(unit);
653+ }
654+
655+ return retval;
656+ }
657+
658+ std::list<std::string> resetCalls()
659+ {
660+ guint len = 0;
661+ GError* error = nullptr;
662+
663+ auto calls = dbus_test_dbus_mock_object_get_method_calls(mock, /* mock */
664+ managerobj, /* manager */
665+ "ResetFailedUnit", /* function */
666+ &len, /* number */
667+ &error /* error */
668+ );
669+
670+ if (error != nullptr)
671+ {
672+ g_warning("Unable to get 'ResetFailedUnit' calls from systemd mock: %s", error->message);
673+ g_error_free(error);
674+ throw std::runtime_error{"Mock disfunctional"};
675+ }
676+
677+ std::list<std::string> retval;
678+
679+ for (unsigned int i = 0; i < len; i++)
680+ {
681+ auto& call = calls[i];
682+ gchar* name = nullptr;
683+
684+ g_variant_get(call.params, "(&s)", &name);
685+
686+ if (name == nullptr)
687+ {
688+ g_warning("Invalid 'name' on 'ResetFailedUnit' call");
689+ continue;
690+ }
691+
692+ retval.emplace_back(name);
693+ }
694+
695+ return retval;
696+ }
697+
698+ void managerClear()
699+ {
700+ GError* error = nullptr;
701+
702+ dbus_test_dbus_mock_object_clear_method_calls(mock, /* mock */
703+ managerobj, /* manager */
704+ &error /* error */
705+ );
706+
707+ if (error != nullptr)
708+ {
709+ g_warning("Unable to clear manager calls: %s", error->message);
710+ g_error_free(error);
711+ throw std::runtime_error{"Mock disfunctional"};
712+ }
713+ }
714+
715+ void managerEmitNew(const std::string& name, const std::string& path)
716+ {
717+ GError* error = nullptr;
718+
719+ dbus_test_dbus_mock_object_emit_signal(mock, managerobj, "UnitNew", G_VARIANT_TYPE("(so)"),
720+ g_variant_new("(so)", name.c_str(), path.c_str()), &error);
721+
722+ if (error != nullptr)
723+ {
724+ g_warning("Unable to emit 'UnitNew': %s", error->message);
725+ g_error_free(error);
726+ throw std::runtime_error{"Mock disfunctional"};
727+ }
728+ }
729+
730+ void managerEmitRemoved(const std::string& name, const std::string& path)
731+ {
732+ GError* error = nullptr;
733+
734+ dbus_test_dbus_mock_object_emit_signal(mock, managerobj, "UnitRemoved", G_VARIANT_TYPE("(so)"),
735+ g_variant_new("(so)", name.c_str(), path.c_str()), &error);
736+
737+ if (error != nullptr)
738+ {
739+ g_warning("Unable to emit 'UnitRemoved': %s", error->message);
740+ g_error_free(error);
741+ throw std::runtime_error{"Mock disfunctional"};
742+ }
743+ }
744+
745+ void managerEmitFailed(const Instance& inst, const std::string& reason = "fail")
746+ {
747+ auto instobj =
748+ std::find_if(insts.begin(), insts.end(), [inst](const std::pair<Instance, DbusTestDbusMockObject*>& item) {
749+ return item.first.job == inst.job && item.first.appid == inst.appid &&
750+ item.first.instanceid == inst.instanceid;
751+ });
752+
753+ if (instobj == insts.end())
754+ {
755+ throw std::runtime_error{"Unable to find instance"};
756+ }
757+
758+ GError* error = nullptr;
759+ dbus_test_dbus_mock_object_update_property(mock, instobj->second, "Result",
760+ g_variant_new_string(reason.c_str()), &error);
761+
762+ if (error != nullptr)
763+ {
764+ g_warning("Unable to set result to 'fail': %s", error->message);
765+ g_error_free(error);
766+ throw std::runtime_error{"Mock disfunctional"};
767+ }
768+ }
769+
770+ std::function<DbusTestTaskState()> stateFunc()
771+ {
772+ return [this] { return dbus_test_task_get_state(DBUS_TEST_TASK(mock)); };
773+ }
774+};
775
776=== modified file 'tests/xdg-data/applications/foo-bar.desktop'
777--- tests/xdg-data/applications/foo-bar.desktop 2016-08-15 16:56:02 +0000
778+++ tests/xdg-data/applications/foo-bar.desktop 2017-03-16 21:55:16 +0000
779@@ -3,3 +3,4 @@
780 Exec=foo-bar
781 Type=Application
782 Icon=foo-bar.png
783+X-Ubuntu-Single-Instance=true

Subscribers

People subscribed via source and target branches