2
* Copyright 2013 Canonical Ltd.
4
* This program is free software: you can redistribute it and/or modify it
5
* under the terms of the GNU General Public License version 3, as published
6
* by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranties of
10
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11
* PURPOSE. See the GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License along
14
* with this program. If not, see <http://www.gnu.org/licenses/>.
17
* Ted Gould <ted.gould@canonical.com>
23
#include <gtest/gtest.h>
25
#include <zeitgeist.h>
29
#include "application.h"
33
#include "ubuntu-app-launch.h"
34
#include "libdbustest/dbus-test.h"
38
class LibUAL : public ::testing::Test
41
DbusTestService* service = NULL;
42
DbusTestDbusMock* mock = NULL;
43
DbusTestDbusMock* cgmock = NULL;
44
GDBusConnection* bus = NULL;
45
std::string last_focus_appid;
46
std::string last_resume_appid;
47
guint resume_timeout = 0;
48
std::shared_ptr<ubuntu::app_launch::Registry> registry;
51
static void focus_cb(const gchar* appid, gpointer user_data)
53
g_debug("Focus Callback: %s", appid);
54
LibUAL* _this = static_cast<LibUAL*>(user_data);
55
_this->last_focus_appid = appid;
58
static void resume_cb(const gchar* appid, gpointer user_data)
60
g_debug("Resume Callback: %s", appid);
61
LibUAL* _this = static_cast<LibUAL*>(user_data);
62
_this->last_resume_appid = appid;
64
if (_this->resume_timeout > 0)
66
_this->pause(_this->resume_timeout);
71
/* Useful debugging stuff, but not on by default. You really want to
72
not get all this noise typically */
73
void debugConnection()
80
DbusTestBustle* bustle = dbus_test_bustle_new("test.bustle");
81
dbus_test_service_add_task(service, DBUS_TEST_TASK(bustle));
82
g_object_unref(bustle);
84
DbusTestProcess* monitor = dbus_test_process_new("dbus-monitor");
85
dbus_test_service_add_task(service, DBUS_TEST_TASK(monitor));
86
g_object_unref(monitor);
91
/* Click DB test mode */
92
g_setenv("TEST_CLICK_DB", "click-db-dir", TRUE);
93
g_setenv("TEST_CLICK_USER", "test-user", TRUE);
95
gchar* linkfarmpath = g_build_filename(CMAKE_SOURCE_DIR, "link-farm", NULL);
96
g_setenv("UBUNTU_APP_LAUNCH_LINK_FARM", linkfarmpath, TRUE);
99
g_setenv("XDG_DATA_DIRS", CMAKE_SOURCE_DIR, TRUE);
100
g_setenv("XDG_CACHE_HOME", CMAKE_SOURCE_DIR "/libertine-data", TRUE);
101
g_setenv("XDG_DATA_HOME", CMAKE_SOURCE_DIR "/libertine-home", TRUE);
103
service = dbus_test_service_new(NULL);
107
mock = dbus_test_dbus_mock_new("com.ubuntu.Upstart");
109
DbusTestDbusMockObject* obj =
110
dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);
112
dbus_test_dbus_mock_object_add_method(mock, obj, "EmitEvent", G_VARIANT_TYPE("(sasb)"), NULL, "", NULL);
114
dbus_test_dbus_mock_object_add_method(mock, obj, "GetJobByName", G_VARIANT_TYPE("s"), G_VARIANT_TYPE("o"),
115
"if args[0] == 'application-click':\n"
116
" ret = dbus.ObjectPath('/com/test/application_click')\n"
117
"elif args[0] == 'application-legacy':\n"
118
" ret = dbus.ObjectPath('/com/test/application_legacy')\n"
119
"elif args[0] == 'untrusted-helper':\n"
120
" ret = dbus.ObjectPath('/com/test/untrusted/helper')\n",
123
dbus_test_dbus_mock_object_add_method(mock, obj, "SetEnv", G_VARIANT_TYPE("(assb)"), NULL, "", NULL);
126
DbusTestDbusMockObject* jobobj =
127
dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
129
dbus_test_dbus_mock_object_add_method(
130
mock, jobobj, "Start", G_VARIANT_TYPE("(asb)"), NULL,
131
"if args[0][0] == 'APP_ID=com.test.good_application_1.2.3':"
132
" raise dbus.exceptions.DBusException('Foo running', name='com.ubuntu.Upstart0_6.Error.AlreadyStarted')",
135
dbus_test_dbus_mock_object_add_method(mock, jobobj, "Stop", G_VARIANT_TYPE("(asb)"), NULL, "", NULL);
137
dbus_test_dbus_mock_object_add_method(mock, jobobj, "GetAllInstances", NULL, G_VARIANT_TYPE("ao"),
138
"ret = [ dbus.ObjectPath('/com/test/app_instance') ]", NULL);
140
DbusTestDbusMockObject* instobj =
141
dbus_test_dbus_mock_get_object(mock, "/com/test/app_instance", "com.ubuntu.Upstart0_6.Instance", NULL);
142
dbus_test_dbus_mock_object_add_property(mock, instobj, "name", G_VARIANT_TYPE_STRING,
143
g_variant_new_string("com.test.good_application_1.2.3"), NULL);
144
gchar* process_var = g_strdup_printf("[('main', %d)]", getpid());
145
dbus_test_dbus_mock_object_add_property(mock, instobj, "processes", G_VARIANT_TYPE("a(si)"),
146
g_variant_new_parsed(process_var), NULL);
150
DbusTestDbusMockObject* ljobobj =
151
dbus_test_dbus_mock_get_object(mock, "/com/test/application_legacy", "com.ubuntu.Upstart0_6.Job", NULL);
153
dbus_test_dbus_mock_object_add_method(mock, ljobobj, "Start", G_VARIANT_TYPE("(asb)"), NULL, "", NULL);
155
dbus_test_dbus_mock_object_add_method(mock, ljobobj, "Stop", G_VARIANT_TYPE("(asb)"), NULL, "", NULL);
157
dbus_test_dbus_mock_object_add_method(mock, ljobobj, "GetAllInstances", NULL, G_VARIANT_TYPE("ao"),
158
"ret = [ dbus.ObjectPath('/com/test/legacy_app_instance') ]", NULL);
160
DbusTestDbusMockObject* linstobj = dbus_test_dbus_mock_get_object(mock, "/com/test/legacy_app_instance",
161
"com.ubuntu.Upstart0_6.Instance", NULL);
162
dbus_test_dbus_mock_object_add_property(mock, linstobj, "name", G_VARIANT_TYPE_STRING,
163
g_variant_new_string("multiple-2342345"), NULL);
164
dbus_test_dbus_mock_object_add_property(mock, linstobj, "processes", G_VARIANT_TYPE("a(si)"),
165
g_variant_new_parsed("[('main', 5678)]"), NULL);
167
/* Untrusted Helper */
168
DbusTestDbusMockObject* uhelperobj =
169
dbus_test_dbus_mock_get_object(mock, "/com/test/untrusted/helper", "com.ubuntu.Upstart0_6.Job", NULL);
171
dbus_test_dbus_mock_object_add_method(mock, uhelperobj, "Start", G_VARIANT_TYPE("(asb)"), NULL, "", NULL);
173
dbus_test_dbus_mock_object_add_method(mock, uhelperobj, "Stop", G_VARIANT_TYPE("(asb)"), NULL, "", NULL);
175
dbus_test_dbus_mock_object_add_method(mock, uhelperobj, "GetAllInstances", NULL, G_VARIANT_TYPE("ao"),
176
"ret = [ dbus.ObjectPath('/com/test/untrusted/helper/instance'), "
177
"dbus.ObjectPath('/com/test/untrusted/helper/multi_instance') ]",
180
DbusTestDbusMockObject* uhelperinstance = dbus_test_dbus_mock_get_object(
181
mock, "/com/test/untrusted/helper/instance", "com.ubuntu.Upstart0_6.Instance", NULL);
182
dbus_test_dbus_mock_object_add_property(mock, uhelperinstance, "name", G_VARIANT_TYPE_STRING,
183
g_variant_new_string("untrusted-type::com.foo_bar_43.23.12"), NULL);
185
DbusTestDbusMockObject* unhelpermulti = dbus_test_dbus_mock_get_object(
186
mock, "/com/test/untrusted/helper/multi_instance", "com.ubuntu.Upstart0_6.Instance", NULL);
187
dbus_test_dbus_mock_object_add_property(
188
mock, unhelpermulti, "name", G_VARIANT_TYPE_STRING,
189
g_variant_new_string("untrusted-type:24034582324132:com.bar_foo_8432.13.1"), NULL);
191
/* Create the cgroup manager mock */
192
cgmock = dbus_test_dbus_mock_new("org.test.cgmock");
193
g_setenv("UBUNTU_APP_LAUNCH_CG_MANAGER_NAME", "org.test.cgmock", TRUE);
195
DbusTestDbusMockObject* cgobject = dbus_test_dbus_mock_get_object(cgmock, "/org/linuxcontainers/cgmanager",
196
"org.linuxcontainers.cgmanager0_0", NULL);
197
dbus_test_dbus_mock_object_add_method(cgmock, cgobject, "GetTasksRecursive", G_VARIANT_TYPE("(ss)"),
198
G_VARIANT_TYPE("ai"), "ret = [100, 200, 300]", NULL);
200
/* Put it together */
201
dbus_test_service_add_task(service, DBUS_TEST_TASK(mock));
202
dbus_test_service_add_task(service, DBUS_TEST_TASK(cgmock));
203
dbus_test_service_start_tasks(service);
205
bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
206
g_dbus_connection_set_exit_on_close(bus, FALSE);
207
g_object_add_weak_pointer(G_OBJECT(bus), (gpointer*)&bus);
209
/* Make sure we pretend the CG manager is just on our bus */
210
g_setenv("UBUNTU_APP_LAUNCH_CG_MANAGER_SESSION_BUS", "YES", TRUE);
212
ASSERT_TRUE(ubuntu_app_launch_observer_add_app_focus(focus_cb, this));
213
ASSERT_TRUE(ubuntu_app_launch_observer_add_app_resume(resume_cb, this));
215
registry = std::make_shared<ubuntu::app_launch::Registry>();
218
virtual void TearDown()
222
ubuntu_app_launch_observer_delete_app_focus(focus_cb, this);
223
ubuntu_app_launch_observer_delete_app_resume(resume_cb, this);
225
g_clear_object(&mock);
226
g_clear_object(&cgmock);
227
g_clear_object(&service);
231
unsigned int cleartry = 0;
232
while (bus != NULL && cleartry < 100)
237
ASSERT_EQ(nullptr, bus);
240
GVariant* find_env(GVariant* env_array, const gchar* var)
243
GVariant* retval = nullptr;
245
for (i = 0; i < g_variant_n_children(env_array); i++)
247
GVariant* child = g_variant_get_child_value(env_array, i);
248
const gchar* envvar = g_variant_get_string(child, nullptr);
250
if (g_str_has_prefix(envvar, var))
252
if (retval != nullptr)
254
g_warning("Found the env var more than once!");
255
g_variant_unref(retval);
263
g_variant_unref(child);
269
gchar* envstr = g_variant_print(env_array, FALSE);
270
g_warning("Unable to find '%s' in '%s'", var, envstr);
277
bool check_env(GVariant* env_array, const gchar* var, const gchar* value)
280
GVariant* val = find_env(env_array, var);
286
const gchar* envvar = g_variant_get_string(val, nullptr);
288
gchar* combined = g_strdup_printf("%s=%s", var, value);
289
if (g_strcmp0(envvar, combined) == 0)
294
g_variant_unref(val);
299
void pause(guint time = 0)
303
GMainLoop* mainloop = g_main_loop_new(NULL, FALSE);
306
[](gpointer pmainloop) -> gboolean
308
g_main_loop_quit(static_cast<GMainLoop*>(pmainloop));
309
return G_SOURCE_REMOVE;
313
g_main_loop_run(mainloop);
315
g_main_loop_unref(mainloop);
318
while (g_main_pending())
320
g_main_iteration(TRUE);
325
TEST_F(LibUAL, StartApplication)
327
DbusTestDbusMockObject* obj =
328
dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
330
/* Basic make sure we can send the event */
331
auto appid = ubuntu::app_launch::AppID::parse("com.test.multiple_first_1.2.3");
332
auto app = ubuntu::app_launch::Application::create(appid, registry);
335
EXPECT_EQ(1, dbus_test_dbus_mock_object_check_method_call(mock, obj, "Start", NULL, NULL));
337
ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
339
/* Now look at the details of the call */
343
const DbusTestDbusMockCall* calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
344
EXPECT_NE(nullptr, calls);
347
EXPECT_STREQ("Start", calls->name);
348
EXPECT_EQ(2, g_variant_n_children(calls->params));
350
GVariant* block = g_variant_get_child_value(calls->params, 1);
351
EXPECT_TRUE(g_variant_get_boolean(block));
352
g_variant_unref(block);
354
GVariant* env = g_variant_get_child_value(calls->params, 0);
355
EXPECT_TRUE(check_env(env, "APP_ID", "com.test.multiple_first_1.2.3"));
356
g_variant_unref(env);
358
ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
360
/* Let's pass some URLs */
361
std::vector<ubuntu::app_launch::Application::URL> urls{
362
ubuntu::app_launch::Application::URL::from_raw("http://ubuntu.com/"),
363
ubuntu::app_launch::Application::URL::from_raw("https://ubuntu.com/"),
364
ubuntu::app_launch::Application::URL::from_raw("file:///home/phablet/test.txt")};
369
calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
370
EXPECT_NE(nullptr, calls);
373
env = g_variant_get_child_value(calls->params, 0);
374
EXPECT_TRUE(check_env(env, "APP_ID", "com.test.multiple_first_1.2.3"));
376
check_env(env, "APP_URIS", "'http://ubuntu.com/' 'https://ubuntu.com/' 'file:///home/phablet/test.txt'"));
377
g_variant_unref(env);
382
TEST_F(LibUAL, StartApplicationTest)
384
DbusTestDbusMockObject* obj =
385
dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
387
/* Basic make sure we can send the event */
388
auto appid = ubuntu::app_launch::AppID::parse("com.test.multiple_first_1.2.3");
389
auto app = ubuntu::app_launch::Application::create(appid, registry);
393
const DbusTestDbusMockCall* calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
394
EXPECT_NE(nullptr, calls);
397
EXPECT_STREQ("Start", calls->name);
398
EXPECT_EQ(2, g_variant_n_children(calls->params));
400
GVariant* block = g_variant_get_child_value(calls->params, 1);
401
EXPECT_TRUE(g_variant_get_boolean(block));
402
g_variant_unref(block);
404
GVariant* env = g_variant_get_child_value(calls->params, 0);
405
EXPECT_TRUE(check_env(env, "APP_ID", "com.test.multiple_first_1.2.3"));
406
EXPECT_TRUE(check_env(env, "QT_LOAD_TESTABILITY", "1"));
407
g_variant_unref(env);
410
TEST_F(LibUAL, StopApplication)
412
DbusTestDbusMockObject* obj =
413
dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
415
auto appid = ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3");
416
auto app = ubuntu::app_launch::Application::create(appid, registry);
418
ASSERT_TRUE(app->hasInstances());
419
EXPECT_EQ(1, app->instances().size());
421
app->instances()[0]->stop();
423
ASSERT_EQ(dbus_test_dbus_mock_object_check_method_call(mock, obj, "Stop", NULL, NULL), 1);
426
/* NOTE: The fact that there is 'libertine-data' in these strings is because
427
we're using one CACHE_HOME for this test suite and the libertine functions
428
need to pull things from there, where these are only comparisons. It's just
429
what value is in the environment variable */
430
TEST_F(LibUAL, ApplicationLog)
432
auto appid = ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3");
433
auto app = ubuntu::app_launch::Application::create(appid, registry);
436
std::string(CMAKE_SOURCE_DIR "/libertine-data/upstart/application-click-com.test.good_application_1.2.3.log"),
437
app->instances()[0]->logPath());
439
appid = ubuntu::app_launch::AppID::find("single");
440
app = ubuntu::app_launch::Application::create(appid, registry);
442
EXPECT_EQ(std::string(CMAKE_SOURCE_DIR "/libertine-data/upstart/application-legacy-single-.log"),
443
app->instances()[0]->logPath());
445
appid = ubuntu::app_launch::AppID::find("multiple");
446
app = ubuntu::app_launch::Application::create(appid, registry);
448
EXPECT_EQ(std::string(CMAKE_SOURCE_DIR "/libertine-data/upstart/application-legacy-multiple-2342345.log"),
449
app->instances()[0]->logPath());
452
TEST_F(LibUAL, ApplicationPid)
454
/* Check bad params */
455
auto appid = ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3");
456
auto app = ubuntu::app_launch::Application::create(appid, registry);
458
EXPECT_FALSE(app->instances()[0]->hasPid(0));
460
/* Check primary pid, which comes from Upstart */
461
EXPECT_EQ(getpid(), app->instances()[0]->primaryPid());
463
auto multiappid = ubuntu::app_launch::AppID::find("multiple");
464
auto multiapp = ubuntu::app_launch::Application::create(multiappid, registry);
465
EXPECT_EQ(5678, multiapp->instances()[0]->primaryPid());
467
/* Look at the full PID list from CG Manager */
468
DbusTestDbusMockObject* cgobject = dbus_test_dbus_mock_get_object(cgmock, "/org/linuxcontainers/cgmanager",
469
"org.linuxcontainers.cgmanager0_0", NULL);
470
const DbusTestDbusMockCall* calls = NULL;
473
/* Click in the set */
474
EXPECT_TRUE(app->instances()[0]->hasPid(100));
475
calls = dbus_test_dbus_mock_object_get_method_calls(cgmock, cgobject, "GetTasksRecursive", &len, NULL);
477
EXPECT_STREQ("GetTasksRecursive", calls->name);
478
EXPECT_TRUE(g_variant_equal(
479
calls->params, g_variant_new("(ss)", "freezer", "upstart/application-click-com.test.good_application_1.2.3")));
480
ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(cgmock, cgobject, NULL));
482
/* Click out of the set */
483
EXPECT_FALSE(app->instances()[0]->hasPid(101));
484
calls = dbus_test_dbus_mock_object_get_method_calls(cgmock, cgobject, "GetTasksRecursive", &len, NULL);
486
EXPECT_STREQ("GetTasksRecursive", calls->name);
487
EXPECT_TRUE(g_variant_equal(
488
calls->params, g_variant_new("(ss)", "freezer", "upstart/application-click-com.test.good_application_1.2.3")));
489
ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(cgmock, cgobject, NULL));
491
/* Legacy Single Instance */
492
auto singleappid = ubuntu::app_launch::AppID::find("single");
493
auto singleapp = ubuntu::app_launch::Application::create(singleappid, registry);
495
EXPECT_TRUE(singleapp->instances()[0]->hasPid(100));
497
calls = dbus_test_dbus_mock_object_get_method_calls(cgmock, cgobject, "GetTasksRecursive", &len, NULL);
499
EXPECT_STREQ("GetTasksRecursive", calls->name);
500
EXPECT_TRUE(g_variant_equal(calls->params, g_variant_new("(ss)", "freezer", "upstart/application-legacy-single-")));
501
ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(cgmock, cgobject, NULL));
503
/* Legacy Multi Instance */
504
EXPECT_TRUE(multiapp->instances()[0]->hasPid(100));
505
calls = dbus_test_dbus_mock_object_get_method_calls(cgmock, cgobject, "GetTasksRecursive", &len, NULL);
507
EXPECT_STREQ("GetTasksRecursive", calls->name);
508
EXPECT_TRUE(g_variant_equal(calls->params,
509
g_variant_new("(ss)", "freezer", "upstart/application-legacy-multiple-2342345")));
510
ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(cgmock, cgobject, NULL));
513
TEST_F(LibUAL, ApplicationId)
515
g_setenv("TEST_CLICK_DB", "click-db-dir", TRUE);
516
g_setenv("TEST_CLICK_USER", "test-user", TRUE);
518
/* Test with current-user-version, should return the version in the manifest */
519
EXPECT_EQ("com.test.good_application_1.2.3",
520
(std::string)ubuntu::app_launch::AppID::discover("com.test.good", "application"));
522
/* Test with version specified, shouldn't even read the manifest */
523
EXPECT_EQ("com.test.good_application_1.2.4",
524
(std::string)ubuntu::app_launch::AppID::discover("com.test.good", "application", "1.2.4"));
526
/* Test with out a version or app, should return the version in the manifest */
527
EXPECT_EQ("com.test.good_application_1.2.3", (std::string)ubuntu::app_launch::AppID::discover(
528
"com.test.good", "first-listed-app", "current-user-version"));
530
/* Make sure we can select the app from a list correctly */
531
EXPECT_EQ("com.test.multiple_first_1.2.3",
532
(std::string)ubuntu::app_launch::AppID::discover(
533
"com.test.multiple", ubuntu::app_launch::AppID::ApplicationWildcard::FIRST_LISTED));
534
EXPECT_EQ("com.test.multiple_first_1.2.3", (std::string)ubuntu::app_launch::AppID::discover("com.test.multiple"));
535
EXPECT_EQ("com.test.multiple_fifth_1.2.3",
536
(std::string)ubuntu::app_launch::AppID::discover(
537
"com.test.multiple", ubuntu::app_launch::AppID::ApplicationWildcard::LAST_LISTED));
538
EXPECT_EQ("", (std::string)ubuntu::app_launch::AppID::discover(
539
"com.test.multiple", ubuntu::app_launch::AppID::ApplicationWildcard::ONLY_LISTED));
540
EXPECT_EQ("com.test.good_application_1.2.3",
541
(std::string)ubuntu::app_launch::AppID::discover(
542
"com.test.good", ubuntu::app_launch::AppID::ApplicationWildcard::ONLY_LISTED));
544
/* A bunch that should be NULL */
545
EXPECT_EQ("", (std::string)ubuntu::app_launch::AppID::discover("com.test.no-hooks"));
546
EXPECT_EQ("", (std::string)ubuntu::app_launch::AppID::discover("com.test.no-json"));
547
EXPECT_EQ("", (std::string)ubuntu::app_launch::AppID::discover("com.test.no-object"));
548
EXPECT_EQ("", (std::string)ubuntu::app_launch::AppID::discover("com.test.no-version"));
550
/* Libertine tests */
551
EXPECT_EQ("", (std::string)ubuntu::app_launch::AppID::discover("container-name"));
552
EXPECT_EQ("", (std::string)ubuntu::app_launch::AppID::discover("container-name", "not-exist"));
553
EXPECT_EQ("container-name_test_0.0", (std::string)ubuntu::app_launch::AppID::discover("container-name", "test"));
554
EXPECT_EQ("container-name_user-app_0.0",
555
(std::string)ubuntu::app_launch::AppID::discover("container-name", "user-app"));
558
TEST_F(LibUAL, AppIdParse)
560
EXPECT_FALSE(ubuntu::app_launch::AppID::parse("com.ubuntu.test_test_123").empty());
561
EXPECT_FALSE(ubuntu::app_launch::AppID::find("inkscape").empty());
563
auto id = ubuntu::app_launch::AppID::parse("com.ubuntu.test_test_123");
565
ASSERT_FALSE(id.empty());
566
EXPECT_EQ("com.ubuntu.test", id.package.value());
567
EXPECT_EQ("test", id.appname.value());
568
EXPECT_EQ("123", id.version.value());
573
TEST_F(LibUAL, ApplicationList)
575
auto apps = ubuntu::app_launch::Registry::runningApps(registry);
577
ASSERT_EQ(2, apps.size());
579
apps.sort([](const std::shared_ptr<ubuntu::app_launch::Application>& a,
580
const std::shared_ptr<ubuntu::app_launch::Application>& b)
582
std::string sa = a->appId();
583
std::string sb = b->appId();
588
EXPECT_EQ("com.test.good_application_1.2.3", (std::string)apps.front()->appId());
589
EXPECT_EQ("multiple", (std::string)apps.back()->appId());
598
static void observer_cb(const gchar* appid, gpointer user_data)
600
observer_data_t* data = (observer_data_t*)user_data;
602
if (data->name == NULL)
606
else if (g_strcmp0(data->name, appid) == 0)
612
TEST_F(LibUAL, StartStopObserver)
614
observer_data_t start_data = {.count = 0, .name = nullptr};
615
observer_data_t stop_data = {.count = 0, .name = nullptr};
617
ASSERT_TRUE(ubuntu_app_launch_observer_add_app_started(observer_cb, &start_data));
618
ASSERT_TRUE(ubuntu_app_launch_observer_add_app_stop(observer_cb, &stop_data));
620
DbusTestDbusMockObject* obj =
621
dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);
624
dbus_test_dbus_mock_object_emit_signal(
625
mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),
626
g_variant_new_parsed("('started', ['JOB=application-click', 'INSTANCE=com.test.good_application_1.2.3'])"),
630
while (g_main_pending())
632
g_main_iteration(TRUE);
635
ASSERT_EQ(start_data.count, 1);
638
dbus_test_dbus_mock_object_emit_signal(
639
mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),
640
g_variant_new_parsed("('stopped', ['JOB=application-click', 'INSTANCE=com.test.good_application_1.2.3'])"),
644
while (g_main_pending())
646
g_main_iteration(TRUE);
649
ASSERT_EQ(stop_data.count, 1);
652
start_data.count = 0;
653
start_data.name = "multiple";
655
dbus_test_dbus_mock_object_emit_signal(
656
mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),
657
g_variant_new_parsed("('started', ['JOB=application-legacy', 'INSTANCE=multiple-234235'])"), NULL);
660
while (g_main_pending())
662
g_main_iteration(TRUE);
665
ASSERT_EQ(start_data.count, 1);
669
stop_data.name = "bar";
671
dbus_test_dbus_mock_object_emit_signal(
672
mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),
673
g_variant_new_parsed("('stopped', ['JOB=application-legacy', 'INSTANCE=bar-9344321'])"), NULL);
676
while (g_main_pending())
678
g_main_iteration(TRUE);
681
ASSERT_EQ(stop_data.count, 1);
683
/* Test Noise Start */
684
start_data.count = 0;
685
start_data.name = "com.test.good_application_1.2.3";
687
stop_data.name = "com.test.good_application_1.2.3";
689
/* A full lifecycle */
690
dbus_test_dbus_mock_object_emit_signal(
691
mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),
692
g_variant_new_parsed("('starting', ['JOB=application-click', 'INSTANCE=com.test.good_application_1.2.3'])"),
694
dbus_test_dbus_mock_object_emit_signal(
695
mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),
696
g_variant_new_parsed("('started', ['JOB=application-click', 'INSTANCE=com.test.good_application_1.2.3'])"),
698
dbus_test_dbus_mock_object_emit_signal(
699
mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),
700
g_variant_new_parsed("('stopping', ['JOB=application-click', 'INSTANCE=com.test.good_application_1.2.3'])"),
702
dbus_test_dbus_mock_object_emit_signal(
703
mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),
704
g_variant_new_parsed("('stopped', ['JOB=application-click', 'INSTANCE=com.test.good_application_1.2.3'])"),
708
while (g_main_pending())
710
g_main_iteration(TRUE);
713
/* Ensure we just signaled once for each */
714
ASSERT_EQ(start_data.count, 1);
715
ASSERT_EQ(stop_data.count, 1);
718
ASSERT_TRUE(ubuntu_app_launch_observer_delete_app_started(observer_cb, &start_data));
719
ASSERT_TRUE(ubuntu_app_launch_observer_delete_app_stop(observer_cb, &stop_data));
722
static GDBusMessage* filter_starting(GDBusConnection* conn,
723
GDBusMessage* message,
727
if (g_strcmp0(g_dbus_message_get_member(message), "UnityStartingSignal") == 0)
729
unsigned int* count = static_cast<unsigned int*>(user_data);
731
g_object_unref(message);
738
static void starting_observer(const gchar* appid, gpointer user_data)
740
std::string* last = static_cast<std::string*>(user_data);
745
TEST_F(LibUAL, StartingResponses)
747
std::string last_observer;
748
unsigned int starting_count = 0;
749
GDBusConnection* session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
750
guint filter = g_dbus_connection_add_filter(session, filter_starting, &starting_count, NULL);
752
EXPECT_TRUE(ubuntu_app_launch_observer_add_app_starting(starting_observer, &last_observer));
754
g_dbus_connection_emit_signal(session, NULL, /* destination */
756
"com.canonical.UbuntuAppLaunch", /* interface */
757
"UnityStartingBroadcast", /* signal */
758
g_variant_new("(s)", "com.test.good_application_1.2.3"), /* params, the same */
763
EXPECT_EQ("com.test.good_application_1.2.3", last_observer);
764
EXPECT_EQ(1, starting_count);
766
EXPECT_TRUE(ubuntu_app_launch_observer_delete_app_starting(starting_observer, &last_observer));
768
g_dbus_connection_remove_filter(session, filter);
769
g_object_unref(session);
772
TEST_F(LibUAL, AppIdTest)
774
auto appid = ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3");
775
auto app = ubuntu::app_launch::Application::create(appid, registry);
778
pause(50); /* Ensure all the events come through */
779
EXPECT_EQ("com.test.good_application_1.2.3", this->last_focus_appid);
780
EXPECT_EQ("com.test.good_application_1.2.3", this->last_resume_appid);
783
GDBusMessage* filter_func_good(GDBusConnection* conn, GDBusMessage* message, gboolean incomming, gpointer user_data)
790
if (g_strcmp0(g_dbus_message_get_path(message), (gchar*)user_data) == 0)
792
GDBusMessage* reply = g_dbus_message_new_method_reply(message);
793
g_dbus_connection_send_message(conn, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
794
g_object_unref(message);
801
TEST_F(LibUAL, UrlSendTest)
803
GDBusConnection* session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
804
guint filter = g_dbus_connection_add_filter(session, filter_func_good,
805
(gpointer) "/com_2etest_2egood_5fapplication_5f1_2e2_2e3", NULL);
807
auto appid = ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3");
808
auto app = ubuntu::app_launch::Application::create(appid, registry);
809
std::vector<ubuntu::app_launch::Application::URL> uris = {
810
ubuntu::app_launch::Application::URL::from_raw("http://www.test.com")};
814
pause(100); /* Ensure all the events come through */
816
EXPECT_EQ("com.test.good_application_1.2.3", this->last_focus_appid);
817
EXPECT_EQ("com.test.good_application_1.2.3", this->last_resume_appid);
819
g_dbus_connection_remove_filter(session, filter);
821
/* Send multiple resume responses to ensure we unsubscribe */
822
/* Multiple to increase our chance of hitting a bad free in the middle,
825
for (i = 0; i < 5; i++)
827
g_dbus_connection_emit_signal(session, NULL, /* destination */
829
"com.canonical.UbuntuAppLaunch", /* interface */
830
"UnityResumeResponse", /* signal */
831
g_variant_new("(s)", "com.test.good_application_1.2.3"), /* params, the same */
834
pause(50); /* Ensure all the events come through */
837
g_object_unref(session);
840
TEST_F(LibUAL, UrlSendNoObjectTest)
842
auto appid = ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3");
843
auto app = ubuntu::app_launch::Application::create(appid, registry);
844
std::vector<ubuntu::app_launch::Application::URL> uris = {
845
ubuntu::app_launch::Application::URL::from_raw("http://www.test.com")};
849
pause(100); /* Ensure all the events come through */
851
EXPECT_EQ("com.test.good_application_1.2.3", this->last_focus_appid);
852
EXPECT_EQ("com.test.good_application_1.2.3", this->last_resume_appid);
855
TEST_F(LibUAL, UnityTimeoutTest)
857
this->resume_timeout = 100;
859
auto appid = ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3");
860
auto app = ubuntu::app_launch::Application::create(appid, registry);
864
pause(1000); /* Ensure all the events come through */
865
EXPECT_EQ("com.test.good_application_1.2.3", this->last_focus_appid);
866
EXPECT_EQ("com.test.good_application_1.2.3", this->last_resume_appid);
869
TEST_F(LibUAL, UnityTimeoutUriTest)
871
this->resume_timeout = 200;
873
auto appid = ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3");
874
auto app = ubuntu::app_launch::Application::create(appid, registry);
875
std::vector<ubuntu::app_launch::Application::URL> uris = {
876
ubuntu::app_launch::Application::URL::from_raw("http://www.test.com")};
880
pause(1000); /* Ensure all the events come through */
881
EXPECT_EQ("com.test.good_application_1.2.3", this->last_focus_appid);
882
EXPECT_EQ("com.test.good_application_1.2.3", this->last_resume_appid);
885
GDBusMessage* filter_respawn(GDBusConnection* conn, GDBusMessage* message, gboolean incomming, gpointer user_data)
887
if (g_strcmp0(g_dbus_message_get_member(message), "UnityResumeResponse") == 0)
889
g_object_unref(message);
896
TEST_F(LibUAL, UnityLostTest)
898
GDBusConnection* session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
899
guint filter = g_dbus_connection_add_filter(session, filter_respawn, NULL, NULL);
901
guint start = g_get_monotonic_time();
903
auto appid = ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3");
904
auto app = ubuntu::app_launch::Application::create(appid, registry);
905
std::vector<ubuntu::app_launch::Application::URL> uris = {
906
ubuntu::app_launch::Application::URL::from_raw("http://www.test.com")};
910
guint end = g_get_monotonic_time();
912
g_debug("Start call time: %d ms", (end - start) / 1000);
913
EXPECT_LT(end - start, 2000 * 1000);
915
pause(1000); /* Ensure all the events come through */
917
EXPECT_EQ("com.test.good_application_1.2.3", this->last_focus_appid);
918
EXPECT_EQ("com.test.good_application_1.2.3", this->last_resume_appid);
920
g_dbus_connection_remove_filter(session, filter);
921
g_object_unref(session);
924
TEST_F(LibUAL, LegacySingleInstance)
926
DbusTestDbusMockObject* obj =
927
dbus_test_dbus_mock_get_object(mock, "/com/test/application_legacy", "com.ubuntu.Upstart0_6.Job", NULL);
929
/* Check for a single-instance app */
930
auto singleappid = ubuntu::app_launch::AppID::find("single");
931
auto singleapp = ubuntu::app_launch::Application::create(singleappid, registry);
936
const DbusTestDbusMockCall* calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
937
EXPECT_NE(nullptr, calls);
940
EXPECT_STREQ("Start", calls->name);
941
EXPECT_EQ(2, g_variant_n_children(calls->params));
943
GVariant* block = g_variant_get_child_value(calls->params, 1);
944
EXPECT_TRUE(g_variant_get_boolean(block));
945
g_variant_unref(block);
947
GVariant* env = g_variant_get_child_value(calls->params, 0);
948
EXPECT_TRUE(check_env(env, "APP_ID", "single"));
949
EXPECT_TRUE(check_env(env, "INSTANCE_ID", ""));
950
g_variant_unref(env);
952
ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
954
/* Check for a multi-instance app */
955
auto multipleappid = ubuntu::app_launch::AppID::find("multiple");
956
auto multipleapp = ubuntu::app_launch::Application::create(multipleappid, registry);
958
multipleapp->launch();
961
calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
962
EXPECT_NE(nullptr, calls);
965
EXPECT_STREQ("Start", calls->name);
966
EXPECT_EQ(2, g_variant_n_children(calls->params));
968
block = g_variant_get_child_value(calls->params, 1);
969
EXPECT_TRUE(g_variant_get_boolean(block));
970
g_variant_unref(block);
972
env = g_variant_get_child_value(calls->params, 0);
973
EXPECT_TRUE(check_env(env, "APP_ID", "multiple"));
974
EXPECT_FALSE(check_env(env, "INSTANCE_ID", ""));
975
g_variant_unref(env);
978
static void failed_observer(const gchar* appid, UbuntuAppLaunchAppFailed reason, gpointer user_data)
980
if (reason == UBUNTU_APP_LAUNCH_APP_FAILED_CRASH)
982
std::string* last = static_cast<std::string*>(user_data);
988
TEST_F(LibUAL, FailingObserver)
990
std::string last_observer;
991
GDBusConnection* session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
993
EXPECT_TRUE(ubuntu_app_launch_observer_add_app_failed(failed_observer, &last_observer));
995
g_dbus_connection_emit_signal(
996
session, NULL, /* destination */
998
"com.canonical.UbuntuAppLaunch", /* interface */
999
"ApplicationFailed", /* signal */
1000
g_variant_new("(ss)", "com.test.good_application_1.2.3", "crash"), /* params, the same */
1005
EXPECT_EQ("com.test.good_application_1.2.3", last_observer);
1007
last_observer.clear();
1009
g_dbus_connection_emit_signal(
1010
session, NULL, /* destination */
1012
"com.canonical.UbuntuAppLaunch", /* interface */
1013
"ApplicationFailed", /* signal */
1014
g_variant_new("(ss)", "com.test.good_application_1.2.3", "blahblah"), /* params, the same */
1019
EXPECT_EQ("com.test.good_application_1.2.3", last_observer);
1021
last_observer.clear();
1023
g_dbus_connection_emit_signal(
1024
session, NULL, /* destination */
1026
"com.canonical.UbuntuAppLaunch", /* interface */
1027
"ApplicationFailed", /* signal */
1028
g_variant_new("(ss)", "com.test.good_application_1.2.3", "start-failure"), /* params, the same */
1033
EXPECT_TRUE(last_observer.empty());
1035
EXPECT_TRUE(ubuntu_app_launch_observer_delete_app_failed(failed_observer, &last_observer));
1037
g_object_unref(session);
1040
TEST_F(LibUAL, StartHelper)
1042
DbusTestDbusMockObject* obj =
1043
dbus_test_dbus_mock_get_object(mock, "/com/test/untrusted/helper", "com.ubuntu.Upstart0_6.Job", NULL);
1045
auto untrusted = ubuntu::app_launch::Helper::Type::from_raw("untrusted-type");
1047
/* Basic make sure we can send the event */
1048
auto appid = ubuntu::app_launch::AppID::parse("com.test.multiple_first_1.2.3");
1049
auto helper = ubuntu::app_launch::Helper::create(untrusted, appid, registry);
1053
EXPECT_EQ(1, dbus_test_dbus_mock_object_check_method_call(mock, obj, "Start", NULL, NULL));
1055
ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
1057
/* Now check a multi out */
1061
auto calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
1062
EXPECT_NE(nullptr, calls);
1065
EXPECT_STREQ("Start", calls->name);
1066
EXPECT_EQ(2, g_variant_n_children(calls->params));
1068
auto block = g_variant_get_child_value(calls->params, 1);
1069
EXPECT_TRUE(g_variant_get_boolean(block));
1070
g_variant_unref(block);
1072
auto env = g_variant_get_child_value(calls->params, 0);
1073
EXPECT_TRUE(check_env(env, "APP_ID", "com.test.multiple_first_1.2.3"));
1074
EXPECT_TRUE(check_env(env, "HELPER_TYPE", "untrusted-type"));
1075
g_variant_unref(env);
1077
ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
1079
/* Let's pass some URLs */
1080
std::vector<ubuntu::app_launch::Helper::URL> urls = {
1081
ubuntu::app_launch::Helper::URL::from_raw("http://ubuntu.com/"),
1082
ubuntu::app_launch::Helper::URL::from_raw("https://ubuntu.com/"),
1083
ubuntu::app_launch::Helper::URL::from_raw("file:///home/phablet/test.txt")};
1084
helper->launch(urls);
1087
calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
1088
EXPECT_NE(nullptr, calls);
1091
env = g_variant_get_child_value(calls->params, 0);
1092
EXPECT_TRUE(check_env(env, "APP_ID", "com.test.multiple_first_1.2.3"));
1094
check_env(env, "APP_URIS", "'http://ubuntu.com/' 'https://ubuntu.com/' 'file:///home/phablet/test.txt'"));
1095
EXPECT_TRUE(check_env(env, "HELPER_TYPE", "untrusted-type"));
1096
EXPECT_FALSE(check_env(env, "INSTANCE_ID", NULL));
1097
g_variant_unref(env);
1102
TEST_F(LibUAL, StopHelper)
1104
DbusTestDbusMockObject* obj =
1105
dbus_test_dbus_mock_get_object(mock, "/com/test/untrusted/helper", "com.ubuntu.Upstart0_6.Job", NULL);
1108
auto untrusted = ubuntu::app_launch::Helper::Type::from_raw("untrusted-type");
1110
auto appid = ubuntu::app_launch::AppID::parse("com.bar_foo_8432.13.1");
1111
auto helper = ubuntu::app_launch::Helper::create(untrusted, appid, registry);
1113
ASSERT_TRUE(helper->hasInstances());
1115
auto instances = helper->instances();
1117
EXPECT_EQ(1, instances.size());
1119
instances[0]->stop();
1121
ASSERT_EQ(dbus_test_dbus_mock_object_check_method_call(mock, obj, "Stop", NULL, NULL), 1);
1124
auto calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Stop", &len, NULL);
1125
EXPECT_NE(nullptr, calls);
1128
EXPECT_STREQ("Stop", calls->name);
1129
EXPECT_EQ(2, g_variant_n_children(calls->params));
1131
auto block = g_variant_get_child_value(calls->params, 1);
1132
EXPECT_TRUE(g_variant_get_boolean(block));
1133
g_variant_unref(block);
1135
auto env = g_variant_get_child_value(calls->params, 0);
1136
EXPECT_TRUE(check_env(env, "APP_ID", "com.bar_foo_8432.13.1"));
1137
EXPECT_TRUE(check_env(env, "HELPER_TYPE", "untrusted-type"));
1138
EXPECT_TRUE(check_env(env, "INSTANCE_ID", "24034582324132"));
1139
g_variant_unref(env);
1141
ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
1146
TEST_F(LibUAL, HelperList)
1148
auto nothelper = ubuntu::app_launch::Helper::Type::from_raw("not-a-type");
1149
auto notlist = ubuntu::app_launch::Registry::runningHelpers(nothelper, registry);
1151
EXPECT_EQ(0, notlist.size());
1153
auto goodhelper = ubuntu::app_launch::Helper::Type::from_raw("untrusted-type");
1154
auto goodlist = ubuntu::app_launch::Registry::runningHelpers(goodhelper, registry);
1156
EXPECT_EQ(2, goodlist.size());
1159
[](const std::shared_ptr<ubuntu::app_launch::Helper>& a, const std::shared_ptr<ubuntu::app_launch::Helper>& b)
1161
std::string sa = a->appId();
1162
std::string sb = b->appId();
1167
EXPECT_EQ("com.bar_foo_8432.13.1", (std::string)goodlist.front()->appId());
1168
EXPECT_EQ("com.foo_bar_43.23.12", (std::string)goodlist.back()->appId());
1170
EXPECT_TRUE(goodlist.front()->hasInstances());
1171
EXPECT_TRUE(goodlist.back()->hasInstances());
1173
EXPECT_EQ(1, goodlist.front()->instances().size());
1174
EXPECT_EQ(1, goodlist.back()->instances().size());
1176
EXPECT_TRUE(goodlist.front()->instances()[0]->isRunning());
1177
EXPECT_TRUE(goodlist.back()->instances()[0]->isRunning());
1185
const gchar* instance;
1186
} helper_observer_data_t;
1188
static void helper_observer_cb(const gchar* appid, const gchar* instance, const gchar* type, gpointer user_data)
1190
helper_observer_data_t* data = (helper_observer_data_t*)user_data;
1192
if (g_strcmp0(data->appid, appid) == 0 && g_strcmp0(data->type, type) == 0 &&
1193
g_strcmp0(data->instance, instance) == 0)
1199
TEST_F(LibUAL, StartStopHelperObserver)
1201
helper_observer_data_t start_data = {
1202
.count = 0, .appid = "com.foo_foo_1.2.3", .type = "my-type-is-scorpio", .instance = nullptr};
1203
helper_observer_data_t stop_data = {
1204
.count = 0, .appid = "com.bar_bar_44.32", .type = "my-type-is-libra", .instance = "1234"};
1206
ASSERT_TRUE(ubuntu_app_launch_observer_add_helper_started(helper_observer_cb, "my-type-is-scorpio", &start_data));
1207
ASSERT_TRUE(ubuntu_app_launch_observer_add_helper_stop(helper_observer_cb, "my-type-is-libra", &stop_data));
1209
DbusTestDbusMockObject* obj =
1210
dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);
1213
dbus_test_dbus_mock_object_emit_signal(
1214
mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),
1215
g_variant_new_parsed("('started', ['JOB=untrusted-helper', 'INSTANCE=my-type-is-scorpio::com.foo_foo_1.2.3'])"),
1219
while (g_main_pending())
1221
g_main_iteration(TRUE);
1224
ASSERT_EQ(start_data.count, 1);
1227
dbus_test_dbus_mock_object_emit_signal(
1228
mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),
1229
g_variant_new_parsed(
1230
"('stopped', ['JOB=untrusted-helper', 'INSTANCE=my-type-is-libra:1234:com.bar_bar_44.32'])"),
1234
while (g_main_pending())
1236
g_main_iteration(TRUE);
1239
ASSERT_EQ(stop_data.count, 1);
1243
ubuntu_app_launch_observer_delete_helper_started(helper_observer_cb, "my-type-is-scorpio", &start_data));
1244
ASSERT_TRUE(ubuntu_app_launch_observer_delete_helper_stop(helper_observer_cb, "my-type-is-libra", &stop_data));
1247
gboolean datain(GIOChannel* source, GIOCondition cond, gpointer data)
1249
gsize* datacnt = static_cast<gsize*>(data);
1252
GError* error = NULL;
1254
g_io_channel_read_line(source, &str, &len, NULL, &error);
1259
g_warning("Unable to read from channel: %s", error->message);
1260
g_error_free(error);
1268
static void signal_increment(GDBusConnection* connection,
1269
const gchar* sender,
1271
const gchar* interface,
1272
const gchar* signal,
1276
guint* count = (guint*)user_data;
1277
g_debug("Count incremented to: %d", *count + 1);
1278
*count = *count + 1;
1281
TEST_F(LibUAL, PauseResume)
1283
g_setenv("UBUNTU_APP_LAUNCH_OOM_PROC_PATH", CMAKE_BINARY_DIR "/libual-proc", 1);
1285
/* Setup some spew */
1287
gint spewstdout = 0;
1288
const gchar* spewline[] = {SPEW_UTILITY, NULL};
1289
ASSERT_TRUE(g_spawn_async_with_pipes(NULL, (gchar**)spewline, NULL, /* environment */
1290
G_SPAWN_DEFAULT, NULL, NULL, /* child setup */
1291
&spewpid, NULL, /* stdin */
1292
&spewstdout, NULL, /* stderr */
1296
GIOChannel* spewoutchan = g_io_channel_unix_new(spewstdout);
1297
g_io_channel_set_flags(spewoutchan, G_IO_FLAG_NONBLOCK, NULL);
1298
g_io_add_watch(spewoutchan, G_IO_IN, datain, &datacnt);
1300
/* Setup our OOM adjust file */
1301
gchar* procdir = g_strdup_printf(CMAKE_BINARY_DIR "/libual-proc/%d", spewpid);
1302
ASSERT_EQ(0, g_mkdir_with_parents(procdir, 0700));
1303
gchar* oomadjfile = g_strdup_printf("%s/oom_score_adj", procdir);
1305
ASSERT_TRUE(g_file_set_contents(oomadjfile, "0", -1, NULL));
1307
/* Setup the cgroup */
1308
g_setenv("UBUNTU_APP_LAUNCH_CG_MANAGER_NAME", "org.test.cgmock2", TRUE);
1309
DbusTestDbusMock* cgmock2 = dbus_test_dbus_mock_new("org.test.cgmock2");
1310
DbusTestDbusMockObject* cgobject = dbus_test_dbus_mock_get_object(cgmock2, "/org/linuxcontainers/cgmanager",
1311
"org.linuxcontainers.cgmanager0_0", NULL);
1312
gchar* pypids = g_strdup_printf("ret = [%d]", spewpid);
1313
dbus_test_dbus_mock_object_add_method(cgmock, cgobject, "GetTasksRecursive", G_VARIANT_TYPE("(ss)"),
1314
G_VARIANT_TYPE("ai"), pypids, NULL);
1317
dbus_test_service_add_task(service, DBUS_TEST_TASK(cgmock2));
1318
dbus_test_task_run(DBUS_TEST_TASK(cgmock2));
1319
g_object_unref(G_OBJECT(cgmock2));
1322
DbusTestDbusMock* zgmock = dbus_test_dbus_mock_new("org.gnome.zeitgeist.Engine");
1323
DbusTestDbusMockObject* zgobj =
1324
dbus_test_dbus_mock_get_object(zgmock, "/org/gnome/zeitgeist/log/activity", "org.gnome.zeitgeist.Log", NULL);
1326
dbus_test_dbus_mock_object_add_method(zgmock, zgobj, "InsertEvents", G_VARIANT_TYPE("a(asaasay)"),
1327
G_VARIANT_TYPE("au"), "ret = [ 0 ]", NULL);
1329
dbus_test_service_add_task(service, DBUS_TEST_TASK(zgmock));
1330
dbus_test_task_run(DBUS_TEST_TASK(zgmock));
1331
g_object_unref(G_OBJECT(zgmock));
1333
/* Give things a chance to start */
1336
g_debug("Giving mocks a chance to start");
1338
} while (dbus_test_task_get_state(DBUS_TEST_TASK(cgmock2)) != DBUS_TEST_TASK_STATE_RUNNING &&
1339
dbus_test_task_get_state(DBUS_TEST_TASK(zgmock)) != DBUS_TEST_TASK_STATE_RUNNING);
1341
/* Setup signal handling */
1342
guint paused_count = 0;
1343
guint resumed_count = 0;
1344
guint paused_signal =
1345
g_dbus_connection_signal_subscribe(bus, nullptr, "com.canonical.UbuntuAppLaunch", "ApplicationPaused", "/",
1346
nullptr, G_DBUS_SIGNAL_FLAGS_NONE, signal_increment, &paused_count, nullptr);
1347
guint resumed_signal = g_dbus_connection_signal_subscribe(
1348
bus, nullptr, "com.canonical.UbuntuAppLaunch", "ApplicationResumed", "/", nullptr, G_DBUS_SIGNAL_FLAGS_NONE,
1349
signal_increment, &resumed_count, nullptr);
1352
EXPECT_NE(0, datacnt);
1356
EXPECT_TRUE(ubuntu_app_launch_pause_application("com.test.good_application_1.2.3"));
1358
pause(0); /* Flush queued events */
1359
datacnt = 0; /* clear it */
1363
/* Check data coming out */
1364
EXPECT_EQ(1, paused_count);
1365
EXPECT_EQ(0, datacnt);
1367
/* Check to make sure we sent the event to ZG */
1369
const DbusTestDbusMockCall* calls =
1370
dbus_test_dbus_mock_object_get_method_calls(zgmock, zgobj, "InsertEvents", &numcalls, NULL);
1372
EXPECT_NE(nullptr, calls);
1373
EXPECT_EQ(1, numcalls);
1375
dbus_test_dbus_mock_object_clear_method_calls(zgmock, zgobj, NULL);
1377
/* Check to ensure we set the OOM score */
1378
gchar* pauseoomscore = NULL;
1379
ASSERT_TRUE(g_file_get_contents(oomadjfile, &pauseoomscore, NULL, NULL));
1380
EXPECT_STREQ("900", pauseoomscore);
1381
g_free(pauseoomscore);
1384
/* Now Resume the App */
1385
EXPECT_TRUE(ubuntu_app_launch_resume_application("com.test.good_application_1.2.3"));
1389
EXPECT_NE(0, datacnt);
1390
EXPECT_EQ(1, resumed_count);
1392
/* Check to make sure we sent the event to ZG */
1394
calls = dbus_test_dbus_mock_object_get_method_calls(zgmock, zgobj, "InsertEvents", &numcalls, NULL);
1396
EXPECT_NE(nullptr, calls);
1397
EXPECT_EQ(1, numcalls);
1399
/* Check to ensure we set the OOM score */
1400
gchar* resumeoomscore = NULL;
1401
ASSERT_TRUE(g_file_get_contents(oomadjfile, &resumeoomscore, NULL, NULL));
1402
EXPECT_STREQ("100", resumeoomscore);
1403
g_free(resumeoomscore);
1406
gchar* killstr = g_strdup_printf("kill -9 %d", spewpid);
1407
ASSERT_TRUE(g_spawn_command_line_sync(killstr, NULL, NULL, NULL, NULL));
1410
g_io_channel_unref(spewoutchan);
1412
g_spawn_command_line_sync("rm -rf " CMAKE_BINARY_DIR "/libual-proc", NULL, NULL, NULL, NULL);
1414
g_dbus_connection_signal_unsubscribe(bus, paused_signal);
1415
g_dbus_connection_signal_unsubscribe(bus, resumed_signal);
1417
/* Kill ZG default instance :-( */
1418
ZeitgeistLog* log = zeitgeist_log_get_default();
1419
g_object_unref(log);
1420
g_object_unref(log);
1425
TEST_F(LibUAL, StartSessionHelper)
1427
DbusTestDbusMockObject* obj =
1428
dbus_test_dbus_mock_get_object(mock, "/com/test/untrusted/helper", "com.ubuntu.Upstart0_6.Job", NULL);
1429
MirConnection* conn = mir_connect_sync("libual-test", "start-session-helper"); // Mocked, doesn't need cleaning up
1430
MirPromptSession* msession = mir_connection_create_prompt_session_sync(conn, 5, nullptr, nullptr);
1432
/* Building a temporary file and making an FD for it */
1433
const char* filedata = "This is some data that we should get on the other side\n";
1434
ASSERT_TRUE(g_file_set_contents(SESSION_TEMP_FILE, filedata, strlen(filedata), nullptr) == TRUE);
1435
int mirfd = open(SESSION_TEMP_FILE, 0);
1436
mir_mock_set_trusted_fd(mirfd);
1438
/* Basic make sure we can send the event */
1439
auto untrusted = ubuntu::app_launch::Helper::Type::from_raw("untrusted-type");
1440
auto appid = ubuntu::app_launch::AppID::parse("com.test.multiple_first_1.2.3");
1441
auto helper = ubuntu::app_launch::Helper::create(untrusted, appid, registry);
1443
helper->launch(msession);
1446
const DbusTestDbusMockCall* calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
1447
EXPECT_NE(nullptr, calls);
1450
EXPECT_STREQ("Start", calls->name);
1451
EXPECT_EQ(2, g_variant_n_children(calls->params));
1453
GVariant* block = g_variant_get_child_value(calls->params, 1);
1454
EXPECT_TRUE(g_variant_get_boolean(block));
1455
g_variant_unref(block);
1457
/* Check the environment */
1458
GVariant* env = g_variant_get_child_value(calls->params, 0);
1459
EXPECT_TRUE(check_env(env, "APP_ID", "com.test.multiple_first_1.2.3"));
1460
EXPECT_TRUE(check_env(env, "HELPER_TYPE", "untrusted-type"));
1462
GVariant* mnamev = find_env(env, "UBUNTU_APP_LAUNCH_DEMANGLE_NAME");
1463
ASSERT_NE(nullptr, mnamev); /* Have to assert because, eh, GVariant */
1464
EXPECT_STREQ(g_dbus_connection_get_unique_name(bus),
1465
g_variant_get_string(mnamev, nullptr) + strlen("UBUNTU_APP_LAUNCH_DEMANGLE_NAME="));
1466
GVariant* mpathv = find_env(env, "UBUNTU_APP_LAUNCH_DEMANGLE_PATH");
1467
ASSERT_NE(nullptr, mpathv); /* Have to assert because, eh, GVariant */
1469
g_variant_unref(env);
1471
/* Setup environment for call */
1472
const gchar* mname = g_variant_get_string(mnamev, nullptr);
1473
mname += strlen("UBUNTU_APP_LAUNCH_DEMANGLE_NAME=");
1474
g_setenv("UBUNTU_APP_LAUNCH_DEMANGLE_NAME", mname, TRUE);
1475
g_variant_unref(mnamev);
1477
const gchar* mpath = g_variant_get_string(mpathv, nullptr);
1478
mpath += strlen("UBUNTU_APP_LAUNCH_DEMANGLE_PATH=");
1479
g_setenv("UBUNTU_APP_LAUNCH_DEMANGLE_PATH", mpath, TRUE);
1480
g_variant_unref(mpathv);
1483
std::promise<std::string> outputpromise;
1487
gchar* socketstdout = nullptr;
1488
GError* error = nullptr;
1489
g_unsetenv("G_MESSAGES_DEBUG");
1491
g_spawn_command_line_sync(SOCKET_DEMANGLER " " SOCKET_TOOL, &socketstdout, nullptr, nullptr, &error);
1493
if (error != nullptr)
1495
fprintf(stderr, "Unable to spawn '" SOCKET_DEMANGLER " " SOCKET_TOOL "': %s\n", error->message);
1496
g_error_free(error);
1497
outputpromise.set_value(std::string(""));
1501
outputpromise.set_value(std::string(socketstdout));
1502
g_free(socketstdout);
1507
auto outputfuture = outputpromise.get_future();
1508
while (outputfuture.wait_for(std::chrono::milliseconds{1}) != std::future_status::ready)
1513
ASSERT_STREQ(filedata, outputfuture.get().c_str());
1515
ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
1520
TEST_F(LibUAL, SetExec)
1522
DbusTestDbusMockObject* obj =
1523
dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);
1525
const char* exec = "lets exec this";
1527
g_setenv("UPSTART_JOB", "fubar", TRUE);
1528
g_unsetenv("UBUNTU_APP_LAUNCH_DEMANGLE_NAME");
1529
EXPECT_TRUE(ubuntu_app_launch_helper_set_exec(exec, NULL));
1532
const DbusTestDbusMockCall* calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "SetEnv", &len, NULL);
1533
ASSERT_NE(nullptr, calls);
1536
gchar* appexecstr = g_strdup_printf("APP_EXEC=%s", exec);
1537
GVariant* appexecenv = g_variant_get_child_value(calls[0].params, 1);
1538
EXPECT_STREQ(appexecstr, g_variant_get_string(appexecenv, nullptr));
1539
g_variant_unref(appexecenv);
1542
ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
1544
/* Now check for the demangler */
1545
g_setenv("UBUNTU_APP_LAUNCH_DEMANGLE_NAME", g_dbus_connection_get_unique_name(bus), TRUE);
1546
EXPECT_TRUE(ubuntu_app_launch_helper_set_exec(exec, NULL));
1548
calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "SetEnv", &len, NULL);
1549
ASSERT_NE(nullptr, calls);
1552
gchar* demangleexecstr = g_strdup_printf("APP_EXEC=%s %s", SOCKET_DEMANGLER_INSTALL, exec);
1553
appexecenv = g_variant_get_child_value(calls[0].params, 1);
1554
EXPECT_STREQ(demangleexecstr, g_variant_get_string(appexecenv, nullptr));
1555
g_variant_unref(appexecenv);
1556
g_free(demangleexecstr);
1558
ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
1560
/* Now check for the directory */
1561
g_setenv("UBUNTU_APP_LAUNCH_DEMANGLE_NAME", g_dbus_connection_get_unique_name(bus), TRUE);
1562
EXPECT_TRUE(ubuntu_app_launch_helper_set_exec(exec, "/not/a/real/directory"));
1564
calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "SetEnv", &len, NULL);
1565
ASSERT_NE(nullptr, calls);
1568
appexecenv = g_variant_get_child_value(calls[1].params, 1);
1569
EXPECT_STREQ("APP_DIR=/not/a/real/directory", g_variant_get_string(appexecenv, nullptr));
1570
g_variant_unref(appexecenv);
1572
ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
1575
TEST_F(LibUAL, AppInfo)
1577
g_setenv("TEST_CLICK_DB", "click-db-dir", TRUE);
1578
g_setenv("TEST_CLICK_USER", "test-user", TRUE);
1580
/* Correct values from a click */
1581
auto appid = ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.4");
1582
auto app = ubuntu::app_launch::Application::create(appid, registry);
1584
EXPECT_TRUE((bool)app->info());
1585
EXPECT_EQ("Application", app->info()->name().value());
1587
/* Correct values from a legacy */
1588
auto barid = ubuntu::app_launch::AppID::find("bar");
1589
EXPECT_THROW(ubuntu::app_launch::Application::create(barid, registry), std::runtime_error);
1591
/* Correct values for libertine */
1592
auto libertineid = ubuntu::app_launch::AppID::parse("container-name_test_0.0");
1593
auto libertine = ubuntu::app_launch::Application::create(libertineid, registry);
1595
auto info = libertine->info();
1596
EXPECT_TRUE((bool)info);
1598
EXPECT_EQ("Test", info->name().value());