~larryprice/ubuntu-app-launch/some-icon-paths-need-merged

« back to all changes in this revision

Viewing changes to tests/libual-cpp-test.cc

  • Committer: CI Train Bot
  • Author(s): Michael Terry, Ted Gould
  • Date: 2016-04-21 19:46:50 UTC
  • mfrom: (144.5.126 app-object)
  • Revision ID: ci-train-bot@canonical.com-20160421194650-mfk7d4hfcjhuyj9m
Add a C++ API for UAL
Approved by: Thomas Voß, PS Jenkins bot

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2013 Canonical Ltd.
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify it
 
5
 * under the terms of the GNU General Public License version 3, as published
 
6
 * by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful, but
 
9
 * WITHOUT ANY WARRANTY; without even the implied warranties of
 
10
 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
 
11
 * PURPOSE.  See the GNU General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License along
 
14
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 * Authors:
 
17
 *     Ted Gould <ted.gould@canonical.com>
 
18
 */
 
19
 
 
20
#include <future>
 
21
#include <thread>
 
22
 
 
23
#include <gtest/gtest.h>
 
24
#include <gio/gio.h>
 
25
#include <zeitgeist.h>
 
26
#include "mir-mock.h"
 
27
 
 
28
#include "registry.h"
 
29
#include "application.h"
 
30
#include "helper.h"
 
31
 
 
32
extern "C" {
 
33
#include "ubuntu-app-launch.h"
 
34
#include "libdbustest/dbus-test.h"
 
35
#include <fcntl.h>
 
36
}
 
37
 
 
38
class LibUAL : public ::testing::Test
 
39
{
 
40
protected:
 
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;
 
49
 
 
50
private:
 
51
    static void focus_cb(const gchar* appid, gpointer user_data)
 
52
    {
 
53
        g_debug("Focus Callback: %s", appid);
 
54
        LibUAL* _this = static_cast<LibUAL*>(user_data);
 
55
        _this->last_focus_appid = appid;
 
56
    }
 
57
 
 
58
    static void resume_cb(const gchar* appid, gpointer user_data)
 
59
    {
 
60
        g_debug("Resume Callback: %s", appid);
 
61
        LibUAL* _this = static_cast<LibUAL*>(user_data);
 
62
        _this->last_resume_appid = appid;
 
63
 
 
64
        if (_this->resume_timeout > 0)
 
65
        {
 
66
            _this->pause(_this->resume_timeout);
 
67
        }
 
68
    }
 
69
 
 
70
protected:
 
71
    /* Useful debugging stuff, but not on by default.  You really want to
 
72
       not get all this noise typically */
 
73
    void debugConnection()
 
74
    {
 
75
        if (true)
 
76
        {
 
77
            return;
 
78
        }
 
79
 
 
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);
 
83
 
 
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);
 
87
    }
 
88
 
 
89
    virtual void SetUp()
 
90
    {
 
91
        /* Click DB test mode */
 
92
        g_setenv("TEST_CLICK_DB", "click-db-dir", TRUE);
 
93
        g_setenv("TEST_CLICK_USER", "test-user", TRUE);
 
94
 
 
95
        gchar* linkfarmpath = g_build_filename(CMAKE_SOURCE_DIR, "link-farm", NULL);
 
96
        g_setenv("UBUNTU_APP_LAUNCH_LINK_FARM", linkfarmpath, TRUE);
 
97
        g_free(linkfarmpath);
 
98
 
 
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);
 
102
 
 
103
        service = dbus_test_service_new(NULL);
 
104
 
 
105
        debugConnection();
 
106
 
 
107
        mock = dbus_test_dbus_mock_new("com.ubuntu.Upstart");
 
108
 
 
109
        DbusTestDbusMockObject* obj =
 
110
            dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);
 
111
 
 
112
        dbus_test_dbus_mock_object_add_method(mock, obj, "EmitEvent", G_VARIANT_TYPE("(sasb)"), NULL, "", NULL);
 
113
 
 
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",
 
121
                                              NULL);
 
122
 
 
123
        dbus_test_dbus_mock_object_add_method(mock, obj, "SetEnv", G_VARIANT_TYPE("(assb)"), NULL, "", NULL);
 
124
 
 
125
        /* Click App */
 
126
        DbusTestDbusMockObject* jobobj =
 
127
            dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
 
128
 
 
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')",
 
133
            NULL);
 
134
 
 
135
        dbus_test_dbus_mock_object_add_method(mock, jobobj, "Stop", G_VARIANT_TYPE("(asb)"), NULL, "", NULL);
 
136
 
 
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);
 
139
 
 
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);
 
147
        g_free(process_var);
 
148
 
 
149
        /*  Legacy App */
 
150
        DbusTestDbusMockObject* ljobobj =
 
151
            dbus_test_dbus_mock_get_object(mock, "/com/test/application_legacy", "com.ubuntu.Upstart0_6.Job", NULL);
 
152
 
 
153
        dbus_test_dbus_mock_object_add_method(mock, ljobobj, "Start", G_VARIANT_TYPE("(asb)"), NULL, "", NULL);
 
154
 
 
155
        dbus_test_dbus_mock_object_add_method(mock, ljobobj, "Stop", G_VARIANT_TYPE("(asb)"), NULL, "", NULL);
 
156
 
 
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);
 
159
 
 
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);
 
166
 
 
167
        /*  Untrusted Helper */
 
168
        DbusTestDbusMockObject* uhelperobj =
 
169
            dbus_test_dbus_mock_get_object(mock, "/com/test/untrusted/helper", "com.ubuntu.Upstart0_6.Job", NULL);
 
170
 
 
171
        dbus_test_dbus_mock_object_add_method(mock, uhelperobj, "Start", G_VARIANT_TYPE("(asb)"), NULL, "", NULL);
 
172
 
 
173
        dbus_test_dbus_mock_object_add_method(mock, uhelperobj, "Stop", G_VARIANT_TYPE("(asb)"), NULL, "", NULL);
 
174
 
 
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') ]",
 
178
                                              NULL);
 
179
 
 
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);
 
184
 
 
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);
 
190
 
 
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);
 
194
 
 
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);
 
199
 
 
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);
 
204
 
 
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);
 
208
 
 
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);
 
211
 
 
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));
 
214
 
 
215
        registry = std::make_shared<ubuntu::app_launch::Registry>();
 
216
    }
 
217
 
 
218
    virtual void TearDown()
 
219
    {
 
220
        registry.reset();
 
221
 
 
222
        ubuntu_app_launch_observer_delete_app_focus(focus_cb, this);
 
223
        ubuntu_app_launch_observer_delete_app_resume(resume_cb, this);
 
224
 
 
225
        g_clear_object(&mock);
 
226
        g_clear_object(&cgmock);
 
227
        g_clear_object(&service);
 
228
 
 
229
        g_object_unref(bus);
 
230
 
 
231
        unsigned int cleartry = 0;
 
232
        while (bus != NULL && cleartry < 100)
 
233
        {
 
234
            pause(100);
 
235
            cleartry++;
 
236
        }
 
237
        ASSERT_EQ(nullptr, bus);
 
238
    }
 
239
 
 
240
    GVariant* find_env(GVariant* env_array, const gchar* var)
 
241
    {
 
242
        unsigned int i;
 
243
        GVariant* retval = nullptr;
 
244
 
 
245
        for (i = 0; i < g_variant_n_children(env_array); i++)
 
246
        {
 
247
            GVariant* child = g_variant_get_child_value(env_array, i);
 
248
            const gchar* envvar = g_variant_get_string(child, nullptr);
 
249
 
 
250
            if (g_str_has_prefix(envvar, var))
 
251
            {
 
252
                if (retval != nullptr)
 
253
                {
 
254
                    g_warning("Found the env var more than once!");
 
255
                    g_variant_unref(retval);
 
256
                    return nullptr;
 
257
                }
 
258
 
 
259
                retval = child;
 
260
            }
 
261
            else
 
262
            {
 
263
                g_variant_unref(child);
 
264
            }
 
265
        }
 
266
 
 
267
        if (!retval)
 
268
        {
 
269
            gchar* envstr = g_variant_print(env_array, FALSE);
 
270
            g_warning("Unable to find '%s' in '%s'", var, envstr);
 
271
            g_free(envstr);
 
272
        }
 
273
 
 
274
        return retval;
 
275
    }
 
276
 
 
277
    bool check_env(GVariant* env_array, const gchar* var, const gchar* value)
 
278
    {
 
279
        bool found = false;
 
280
        GVariant* val = find_env(env_array, var);
 
281
        if (val == nullptr)
 
282
        {
 
283
            return false;
 
284
        }
 
285
 
 
286
        const gchar* envvar = g_variant_get_string(val, nullptr);
 
287
 
 
288
        gchar* combined = g_strdup_printf("%s=%s", var, value);
 
289
        if (g_strcmp0(envvar, combined) == 0)
 
290
        {
 
291
            found = true;
 
292
        }
 
293
 
 
294
        g_variant_unref(val);
 
295
 
 
296
        return found;
 
297
    }
 
298
 
 
299
    void pause(guint time = 0)
 
300
    {
 
301
        if (time > 0)
 
302
        {
 
303
            GMainLoop* mainloop = g_main_loop_new(NULL, FALSE);
 
304
 
 
305
            g_timeout_add(time,
 
306
                          [](gpointer pmainloop) -> gboolean
 
307
                          {
 
308
                              g_main_loop_quit(static_cast<GMainLoop*>(pmainloop));
 
309
                              return G_SOURCE_REMOVE;
 
310
                          },
 
311
                          mainloop);
 
312
 
 
313
            g_main_loop_run(mainloop);
 
314
 
 
315
            g_main_loop_unref(mainloop);
 
316
        }
 
317
 
 
318
        while (g_main_pending())
 
319
        {
 
320
            g_main_iteration(TRUE);
 
321
        }
 
322
    }
 
323
};
 
324
 
 
325
TEST_F(LibUAL, StartApplication)
 
326
{
 
327
    DbusTestDbusMockObject* obj =
 
328
        dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
 
329
 
 
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);
 
333
    app->launch();
 
334
 
 
335
    EXPECT_EQ(1, dbus_test_dbus_mock_object_check_method_call(mock, obj, "Start", NULL, NULL));
 
336
 
 
337
    ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
 
338
 
 
339
    /* Now look at the details of the call */
 
340
    app->launch();
 
341
 
 
342
    guint len = 0;
 
343
    const DbusTestDbusMockCall* calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
 
344
    EXPECT_NE(nullptr, calls);
 
345
    EXPECT_EQ(1, len);
 
346
 
 
347
    EXPECT_STREQ("Start", calls->name);
 
348
    EXPECT_EQ(2, g_variant_n_children(calls->params));
 
349
 
 
350
    GVariant* block = g_variant_get_child_value(calls->params, 1);
 
351
    EXPECT_TRUE(g_variant_get_boolean(block));
 
352
    g_variant_unref(block);
 
353
 
 
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);
 
357
 
 
358
    ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
 
359
 
 
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")};
 
365
 
 
366
    app->launch(urls);
 
367
 
 
368
    len = 0;
 
369
    calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
 
370
    EXPECT_NE(nullptr, calls);
 
371
    EXPECT_EQ(1, len);
 
372
 
 
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"));
 
375
    EXPECT_TRUE(
 
376
        check_env(env, "APP_URIS", "'http://ubuntu.com/' 'https://ubuntu.com/' 'file:///home/phablet/test.txt'"));
 
377
    g_variant_unref(env);
 
378
 
 
379
    return;
 
380
}
 
381
 
 
382
TEST_F(LibUAL, StartApplicationTest)
 
383
{
 
384
    DbusTestDbusMockObject* obj =
 
385
        dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
 
386
 
 
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);
 
390
    app->launchTest();
 
391
 
 
392
    guint len = 0;
 
393
    const DbusTestDbusMockCall* calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
 
394
    EXPECT_NE(nullptr, calls);
 
395
    EXPECT_EQ(1, len);
 
396
 
 
397
    EXPECT_STREQ("Start", calls->name);
 
398
    EXPECT_EQ(2, g_variant_n_children(calls->params));
 
399
 
 
400
    GVariant* block = g_variant_get_child_value(calls->params, 1);
 
401
    EXPECT_TRUE(g_variant_get_boolean(block));
 
402
    g_variant_unref(block);
 
403
 
 
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);
 
408
}
 
409
 
 
410
TEST_F(LibUAL, StopApplication)
 
411
{
 
412
    DbusTestDbusMockObject* obj =
 
413
        dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
 
414
 
 
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);
 
417
 
 
418
    ASSERT_TRUE(app->hasInstances());
 
419
    EXPECT_EQ(1, app->instances().size());
 
420
 
 
421
    app->instances()[0]->stop();
 
422
 
 
423
    ASSERT_EQ(dbus_test_dbus_mock_object_check_method_call(mock, obj, "Stop", NULL, NULL), 1);
 
424
}
 
425
 
 
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)
 
431
{
 
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);
 
434
 
 
435
    EXPECT_EQ(
 
436
        std::string(CMAKE_SOURCE_DIR "/libertine-data/upstart/application-click-com.test.good_application_1.2.3.log"),
 
437
        app->instances()[0]->logPath());
 
438
 
 
439
    appid = ubuntu::app_launch::AppID::find("single");
 
440
    app = ubuntu::app_launch::Application::create(appid, registry);
 
441
 
 
442
    EXPECT_EQ(std::string(CMAKE_SOURCE_DIR "/libertine-data/upstart/application-legacy-single-.log"),
 
443
              app->instances()[0]->logPath());
 
444
 
 
445
    appid = ubuntu::app_launch::AppID::find("multiple");
 
446
    app = ubuntu::app_launch::Application::create(appid, registry);
 
447
 
 
448
    EXPECT_EQ(std::string(CMAKE_SOURCE_DIR "/libertine-data/upstart/application-legacy-multiple-2342345.log"),
 
449
              app->instances()[0]->logPath());
 
450
}
 
451
 
 
452
TEST_F(LibUAL, ApplicationPid)
 
453
{
 
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);
 
457
 
 
458
    EXPECT_FALSE(app->instances()[0]->hasPid(0));
 
459
 
 
460
    /* Check primary pid, which comes from Upstart */
 
461
    EXPECT_EQ(getpid(), app->instances()[0]->primaryPid());
 
462
 
 
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());
 
466
 
 
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;
 
471
    guint len = 0;
 
472
 
 
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);
 
476
    EXPECT_EQ(1, len);
 
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));
 
481
 
 
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);
 
485
    EXPECT_EQ(1, len);
 
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));
 
490
 
 
491
    /* Legacy Single Instance */
 
492
    auto singleappid = ubuntu::app_launch::AppID::find("single");
 
493
    auto singleapp = ubuntu::app_launch::Application::create(singleappid, registry);
 
494
 
 
495
    EXPECT_TRUE(singleapp->instances()[0]->hasPid(100));
 
496
 
 
497
    calls = dbus_test_dbus_mock_object_get_method_calls(cgmock, cgobject, "GetTasksRecursive", &len, NULL);
 
498
    EXPECT_EQ(1, len);
 
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));
 
502
 
 
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);
 
506
    EXPECT_EQ(1, len);
 
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));
 
511
}
 
512
 
 
513
TEST_F(LibUAL, ApplicationId)
 
514
{
 
515
    g_setenv("TEST_CLICK_DB", "click-db-dir", TRUE);
 
516
    g_setenv("TEST_CLICK_USER", "test-user", TRUE);
 
517
 
 
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"));
 
521
 
 
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"));
 
525
 
 
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"));
 
529
 
 
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));
 
543
 
 
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"));
 
549
 
 
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"));
 
556
}
 
557
 
 
558
TEST_F(LibUAL, AppIdParse)
 
559
{
 
560
    EXPECT_FALSE(ubuntu::app_launch::AppID::parse("com.ubuntu.test_test_123").empty());
 
561
    EXPECT_FALSE(ubuntu::app_launch::AppID::find("inkscape").empty());
 
562
 
 
563
    auto id = ubuntu::app_launch::AppID::parse("com.ubuntu.test_test_123");
 
564
 
 
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());
 
569
 
 
570
    return;
 
571
}
 
572
 
 
573
TEST_F(LibUAL, ApplicationList)
 
574
{
 
575
    auto apps = ubuntu::app_launch::Registry::runningApps(registry);
 
576
 
 
577
    ASSERT_EQ(2, apps.size());
 
578
 
 
579
    apps.sort([](const std::shared_ptr<ubuntu::app_launch::Application>& a,
 
580
                 const std::shared_ptr<ubuntu::app_launch::Application>& b)
 
581
              {
 
582
                  std::string sa = a->appId();
 
583
                  std::string sb = b->appId();
 
584
 
 
585
                  return sa < sb;
 
586
              });
 
587
 
 
588
    EXPECT_EQ("com.test.good_application_1.2.3", (std::string)apps.front()->appId());
 
589
    EXPECT_EQ("multiple", (std::string)apps.back()->appId());
 
590
}
 
591
 
 
592
typedef struct
 
593
{
 
594
    unsigned int count;
 
595
    const gchar* name;
 
596
} observer_data_t;
 
597
 
 
598
static void observer_cb(const gchar* appid, gpointer user_data)
 
599
{
 
600
    observer_data_t* data = (observer_data_t*)user_data;
 
601
 
 
602
    if (data->name == NULL)
 
603
    {
 
604
        data->count++;
 
605
    }
 
606
    else if (g_strcmp0(data->name, appid) == 0)
 
607
    {
 
608
        data->count++;
 
609
    }
 
610
}
 
611
 
 
612
TEST_F(LibUAL, StartStopObserver)
 
613
{
 
614
    observer_data_t start_data = {.count = 0, .name = nullptr};
 
615
    observer_data_t stop_data = {.count = 0, .name = nullptr};
 
616
 
 
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));
 
619
 
 
620
    DbusTestDbusMockObject* obj =
 
621
        dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);
 
622
 
 
623
    /* Basic start */
 
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'])"),
 
627
        NULL);
 
628
 
 
629
    g_usleep(100000);
 
630
    while (g_main_pending())
 
631
    {
 
632
        g_main_iteration(TRUE);
 
633
    }
 
634
 
 
635
    ASSERT_EQ(start_data.count, 1);
 
636
 
 
637
    /* Basic stop */
 
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'])"),
 
641
        NULL);
 
642
 
 
643
    g_usleep(100000);
 
644
    while (g_main_pending())
 
645
    {
 
646
        g_main_iteration(TRUE);
 
647
    }
 
648
 
 
649
    ASSERT_EQ(stop_data.count, 1);
 
650
 
 
651
    /* Start legacy */
 
652
    start_data.count = 0;
 
653
    start_data.name = "multiple";
 
654
 
 
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);
 
658
 
 
659
    g_usleep(100000);
 
660
    while (g_main_pending())
 
661
    {
 
662
        g_main_iteration(TRUE);
 
663
    }
 
664
 
 
665
    ASSERT_EQ(start_data.count, 1);
 
666
 
 
667
    /* Legacy stop */
 
668
    stop_data.count = 0;
 
669
    stop_data.name = "bar";
 
670
 
 
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);
 
674
 
 
675
    g_usleep(100000);
 
676
    while (g_main_pending())
 
677
    {
 
678
        g_main_iteration(TRUE);
 
679
    }
 
680
 
 
681
    ASSERT_EQ(stop_data.count, 1);
 
682
 
 
683
    /* Test Noise Start */
 
684
    start_data.count = 0;
 
685
    start_data.name = "com.test.good_application_1.2.3";
 
686
    stop_data.count = 0;
 
687
    stop_data.name = "com.test.good_application_1.2.3";
 
688
 
 
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'])"),
 
693
        NULL);
 
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'])"),
 
697
        NULL);
 
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'])"),
 
701
        NULL);
 
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'])"),
 
705
        NULL);
 
706
 
 
707
    g_usleep(100000);
 
708
    while (g_main_pending())
 
709
    {
 
710
        g_main_iteration(TRUE);
 
711
    }
 
712
 
 
713
    /* Ensure we just signaled once for each */
 
714
    ASSERT_EQ(start_data.count, 1);
 
715
    ASSERT_EQ(stop_data.count, 1);
 
716
 
 
717
    /* Remove */
 
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));
 
720
}
 
721
 
 
722
static GDBusMessage* filter_starting(GDBusConnection* conn,
 
723
                                     GDBusMessage* message,
 
724
                                     gboolean incomming,
 
725
                                     gpointer user_data)
 
726
{
 
727
    if (g_strcmp0(g_dbus_message_get_member(message), "UnityStartingSignal") == 0)
 
728
    {
 
729
        unsigned int* count = static_cast<unsigned int*>(user_data);
 
730
        (*count)++;
 
731
        g_object_unref(message);
 
732
        return NULL;
 
733
    }
 
734
 
 
735
    return message;
 
736
}
 
737
 
 
738
static void starting_observer(const gchar* appid, gpointer user_data)
 
739
{
 
740
    std::string* last = static_cast<std::string*>(user_data);
 
741
    *last = appid;
 
742
    return;
 
743
}
 
744
 
 
745
TEST_F(LibUAL, StartingResponses)
 
746
{
 
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);
 
751
 
 
752
    EXPECT_TRUE(ubuntu_app_launch_observer_add_app_starting(starting_observer, &last_observer));
 
753
 
 
754
    g_dbus_connection_emit_signal(session, NULL,                                           /* destination */
 
755
                                  "/",                                                     /* path */
 
756
                                  "com.canonical.UbuntuAppLaunch",                         /* interface */
 
757
                                  "UnityStartingBroadcast",                                /* signal */
 
758
                                  g_variant_new("(s)", "com.test.good_application_1.2.3"), /* params, the same */
 
759
                                  NULL);
 
760
 
 
761
    pause(100);
 
762
 
 
763
    EXPECT_EQ("com.test.good_application_1.2.3", last_observer);
 
764
    EXPECT_EQ(1, starting_count);
 
765
 
 
766
    EXPECT_TRUE(ubuntu_app_launch_observer_delete_app_starting(starting_observer, &last_observer));
 
767
 
 
768
    g_dbus_connection_remove_filter(session, filter);
 
769
    g_object_unref(session);
 
770
}
 
771
 
 
772
TEST_F(LibUAL, AppIdTest)
 
773
{
 
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);
 
776
    app->launch();
 
777
 
 
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);
 
781
}
 
782
 
 
783
GDBusMessage* filter_func_good(GDBusConnection* conn, GDBusMessage* message, gboolean incomming, gpointer user_data)
 
784
{
 
785
    if (!incomming)
 
786
    {
 
787
        return message;
 
788
    }
 
789
 
 
790
    if (g_strcmp0(g_dbus_message_get_path(message), (gchar*)user_data) == 0)
 
791
    {
 
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);
 
795
        return NULL;
 
796
    }
 
797
 
 
798
    return message;
 
799
}
 
800
 
 
801
TEST_F(LibUAL, UrlSendTest)
 
802
{
 
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);
 
806
 
 
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")};
 
811
 
 
812
    app->launch(uris);
 
813
 
 
814
    pause(100); /* Ensure all the events come through */
 
815
 
 
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);
 
818
 
 
819
    g_dbus_connection_remove_filter(session, filter);
 
820
 
 
821
    /* Send multiple resume responses to ensure we unsubscribe */
 
822
    /* Multiple to increase our chance of hitting a bad free in the middle,
 
823
       fun with async! */
 
824
    int i;
 
825
    for (i = 0; i < 5; i++)
 
826
    {
 
827
        g_dbus_connection_emit_signal(session, NULL,                                           /* destination */
 
828
                                      "/",                                                     /* path */
 
829
                                      "com.canonical.UbuntuAppLaunch",                         /* interface */
 
830
                                      "UnityResumeResponse",                                   /* signal */
 
831
                                      g_variant_new("(s)", "com.test.good_application_1.2.3"), /* params, the same */
 
832
                                      NULL);
 
833
 
 
834
        pause(50); /* Ensure all the events come through */
 
835
    }
 
836
 
 
837
    g_object_unref(session);
 
838
}
 
839
 
 
840
TEST_F(LibUAL, UrlSendNoObjectTest)
 
841
{
 
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")};
 
846
 
 
847
    app->launch(uris);
 
848
 
 
849
    pause(100); /* Ensure all the events come through */
 
850
 
 
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);
 
853
}
 
854
 
 
855
TEST_F(LibUAL, UnityTimeoutTest)
 
856
{
 
857
    this->resume_timeout = 100;
 
858
 
 
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);
 
861
 
 
862
    app->launch();
 
863
 
 
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);
 
867
}
 
868
 
 
869
TEST_F(LibUAL, UnityTimeoutUriTest)
 
870
{
 
871
    this->resume_timeout = 200;
 
872
 
 
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")};
 
877
 
 
878
    app->launch(uris);
 
879
 
 
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);
 
883
}
 
884
 
 
885
GDBusMessage* filter_respawn(GDBusConnection* conn, GDBusMessage* message, gboolean incomming, gpointer user_data)
 
886
{
 
887
    if (g_strcmp0(g_dbus_message_get_member(message), "UnityResumeResponse") == 0)
 
888
    {
 
889
        g_object_unref(message);
 
890
        return NULL;
 
891
    }
 
892
 
 
893
    return message;
 
894
}
 
895
 
 
896
TEST_F(LibUAL, UnityLostTest)
 
897
{
 
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);
 
900
 
 
901
    guint start = g_get_monotonic_time();
 
902
 
 
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")};
 
907
 
 
908
    app->launch(uris);
 
909
 
 
910
    guint end = g_get_monotonic_time();
 
911
 
 
912
    g_debug("Start call time: %d ms", (end - start) / 1000);
 
913
    EXPECT_LT(end - start, 2000 * 1000);
 
914
 
 
915
    pause(1000); /* Ensure all the events come through */
 
916
 
 
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);
 
919
 
 
920
    g_dbus_connection_remove_filter(session, filter);
 
921
    g_object_unref(session);
 
922
}
 
923
 
 
924
TEST_F(LibUAL, LegacySingleInstance)
 
925
{
 
926
    DbusTestDbusMockObject* obj =
 
927
        dbus_test_dbus_mock_get_object(mock, "/com/test/application_legacy", "com.ubuntu.Upstart0_6.Job", NULL);
 
928
 
 
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);
 
932
 
 
933
    singleapp->launch();
 
934
 
 
935
    guint len = 0;
 
936
    const DbusTestDbusMockCall* calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
 
937
    EXPECT_NE(nullptr, calls);
 
938
    EXPECT_EQ(1, len);
 
939
 
 
940
    EXPECT_STREQ("Start", calls->name);
 
941
    EXPECT_EQ(2, g_variant_n_children(calls->params));
 
942
 
 
943
    GVariant* block = g_variant_get_child_value(calls->params, 1);
 
944
    EXPECT_TRUE(g_variant_get_boolean(block));
 
945
    g_variant_unref(block);
 
946
 
 
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);
 
951
 
 
952
    ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
 
953
 
 
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);
 
957
 
 
958
    multipleapp->launch();
 
959
 
 
960
    len = 0;
 
961
    calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
 
962
    EXPECT_NE(nullptr, calls);
 
963
    EXPECT_EQ(1, len);
 
964
 
 
965
    EXPECT_STREQ("Start", calls->name);
 
966
    EXPECT_EQ(2, g_variant_n_children(calls->params));
 
967
 
 
968
    block = g_variant_get_child_value(calls->params, 1);
 
969
    EXPECT_TRUE(g_variant_get_boolean(block));
 
970
    g_variant_unref(block);
 
971
 
 
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);
 
976
}
 
977
 
 
978
static void failed_observer(const gchar* appid, UbuntuAppLaunchAppFailed reason, gpointer user_data)
 
979
{
 
980
    if (reason == UBUNTU_APP_LAUNCH_APP_FAILED_CRASH)
 
981
    {
 
982
        std::string* last = static_cast<std::string*>(user_data);
 
983
        *last = appid;
 
984
    }
 
985
    return;
 
986
}
 
987
 
 
988
TEST_F(LibUAL, FailingObserver)
 
989
{
 
990
    std::string last_observer;
 
991
    GDBusConnection* session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
 
992
 
 
993
    EXPECT_TRUE(ubuntu_app_launch_observer_add_app_failed(failed_observer, &last_observer));
 
994
 
 
995
    g_dbus_connection_emit_signal(
 
996
        session, NULL,                                                     /* destination */
 
997
        "/",                                                               /* path */
 
998
        "com.canonical.UbuntuAppLaunch",                                   /* interface */
 
999
        "ApplicationFailed",                                               /* signal */
 
1000
        g_variant_new("(ss)", "com.test.good_application_1.2.3", "crash"), /* params, the same */
 
1001
        NULL);
 
1002
 
 
1003
    pause(100);
 
1004
 
 
1005
    EXPECT_EQ("com.test.good_application_1.2.3", last_observer);
 
1006
 
 
1007
    last_observer.clear();
 
1008
 
 
1009
    g_dbus_connection_emit_signal(
 
1010
        session, NULL,                                                        /* destination */
 
1011
        "/",                                                                  /* path */
 
1012
        "com.canonical.UbuntuAppLaunch",                                      /* interface */
 
1013
        "ApplicationFailed",                                                  /* signal */
 
1014
        g_variant_new("(ss)", "com.test.good_application_1.2.3", "blahblah"), /* params, the same */
 
1015
        NULL);
 
1016
 
 
1017
    pause(100);
 
1018
 
 
1019
    EXPECT_EQ("com.test.good_application_1.2.3", last_observer);
 
1020
 
 
1021
    last_observer.clear();
 
1022
 
 
1023
    g_dbus_connection_emit_signal(
 
1024
        session, NULL,                                                             /* destination */
 
1025
        "/",                                                                       /* path */
 
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 */
 
1029
        NULL);
 
1030
 
 
1031
    pause(100);
 
1032
 
 
1033
    EXPECT_TRUE(last_observer.empty());
 
1034
 
 
1035
    EXPECT_TRUE(ubuntu_app_launch_observer_delete_app_failed(failed_observer, &last_observer));
 
1036
 
 
1037
    g_object_unref(session);
 
1038
}
 
1039
 
 
1040
TEST_F(LibUAL, StartHelper)
 
1041
{
 
1042
    DbusTestDbusMockObject* obj =
 
1043
        dbus_test_dbus_mock_get_object(mock, "/com/test/untrusted/helper", "com.ubuntu.Upstart0_6.Job", NULL);
 
1044
 
 
1045
    auto untrusted = ubuntu::app_launch::Helper::Type::from_raw("untrusted-type");
 
1046
 
 
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);
 
1050
 
 
1051
    helper->launch();
 
1052
 
 
1053
    EXPECT_EQ(1, dbus_test_dbus_mock_object_check_method_call(mock, obj, "Start", NULL, NULL));
 
1054
 
 
1055
    ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
 
1056
 
 
1057
    /* Now check a multi out */
 
1058
    helper->launch();
 
1059
 
 
1060
    guint len = 0;
 
1061
    auto calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
 
1062
    EXPECT_NE(nullptr, calls);
 
1063
    EXPECT_EQ(1, len);
 
1064
 
 
1065
    EXPECT_STREQ("Start", calls->name);
 
1066
    EXPECT_EQ(2, g_variant_n_children(calls->params));
 
1067
 
 
1068
    auto block = g_variant_get_child_value(calls->params, 1);
 
1069
    EXPECT_TRUE(g_variant_get_boolean(block));
 
1070
    g_variant_unref(block);
 
1071
 
 
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);
 
1076
 
 
1077
    ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
 
1078
 
 
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);
 
1085
 
 
1086
    len = 0;
 
1087
    calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
 
1088
    EXPECT_NE(nullptr, calls);
 
1089
    EXPECT_EQ(1, len);
 
1090
 
 
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"));
 
1093
    EXPECT_TRUE(
 
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);
 
1098
 
 
1099
    return;
 
1100
}
 
1101
 
 
1102
TEST_F(LibUAL, StopHelper)
 
1103
{
 
1104
    DbusTestDbusMockObject* obj =
 
1105
        dbus_test_dbus_mock_get_object(mock, "/com/test/untrusted/helper", "com.ubuntu.Upstart0_6.Job", NULL);
 
1106
 
 
1107
    /* Multi helper */
 
1108
    auto untrusted = ubuntu::app_launch::Helper::Type::from_raw("untrusted-type");
 
1109
 
 
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);
 
1112
 
 
1113
    ASSERT_TRUE(helper->hasInstances());
 
1114
 
 
1115
    auto instances = helper->instances();
 
1116
 
 
1117
    EXPECT_EQ(1, instances.size());
 
1118
 
 
1119
    instances[0]->stop();
 
1120
 
 
1121
    ASSERT_EQ(dbus_test_dbus_mock_object_check_method_call(mock, obj, "Stop", NULL, NULL), 1);
 
1122
 
 
1123
    guint len = 0;
 
1124
    auto calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Stop", &len, NULL);
 
1125
    EXPECT_NE(nullptr, calls);
 
1126
    EXPECT_EQ(1, len);
 
1127
 
 
1128
    EXPECT_STREQ("Stop", calls->name);
 
1129
    EXPECT_EQ(2, g_variant_n_children(calls->params));
 
1130
 
 
1131
    auto block = g_variant_get_child_value(calls->params, 1);
 
1132
    EXPECT_TRUE(g_variant_get_boolean(block));
 
1133
    g_variant_unref(block);
 
1134
 
 
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);
 
1140
 
 
1141
    ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
 
1142
 
 
1143
    return;
 
1144
}
 
1145
 
 
1146
TEST_F(LibUAL, HelperList)
 
1147
{
 
1148
    auto nothelper = ubuntu::app_launch::Helper::Type::from_raw("not-a-type");
 
1149
    auto notlist = ubuntu::app_launch::Registry::runningHelpers(nothelper, registry);
 
1150
 
 
1151
    EXPECT_EQ(0, notlist.size());
 
1152
 
 
1153
    auto goodhelper = ubuntu::app_launch::Helper::Type::from_raw("untrusted-type");
 
1154
    auto goodlist = ubuntu::app_launch::Registry::runningHelpers(goodhelper, registry);
 
1155
 
 
1156
    EXPECT_EQ(2, goodlist.size());
 
1157
 
 
1158
    goodlist.sort(
 
1159
        [](const std::shared_ptr<ubuntu::app_launch::Helper>& a, const std::shared_ptr<ubuntu::app_launch::Helper>& b)
 
1160
        {
 
1161
            std::string sa = a->appId();
 
1162
            std::string sb = b->appId();
 
1163
 
 
1164
            return sa < sb;
 
1165
        });
 
1166
 
 
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());
 
1169
 
 
1170
    EXPECT_TRUE(goodlist.front()->hasInstances());
 
1171
    EXPECT_TRUE(goodlist.back()->hasInstances());
 
1172
 
 
1173
    EXPECT_EQ(1, goodlist.front()->instances().size());
 
1174
    EXPECT_EQ(1, goodlist.back()->instances().size());
 
1175
 
 
1176
    EXPECT_TRUE(goodlist.front()->instances()[0]->isRunning());
 
1177
    EXPECT_TRUE(goodlist.back()->instances()[0]->isRunning());
 
1178
}
 
1179
 
 
1180
typedef struct
 
1181
{
 
1182
    unsigned int count;
 
1183
    const gchar* appid;
 
1184
    const gchar* type;
 
1185
    const gchar* instance;
 
1186
} helper_observer_data_t;
 
1187
 
 
1188
static void helper_observer_cb(const gchar* appid, const gchar* instance, const gchar* type, gpointer user_data)
 
1189
{
 
1190
    helper_observer_data_t* data = (helper_observer_data_t*)user_data;
 
1191
 
 
1192
    if (g_strcmp0(data->appid, appid) == 0 && g_strcmp0(data->type, type) == 0 &&
 
1193
        g_strcmp0(data->instance, instance) == 0)
 
1194
    {
 
1195
        data->count++;
 
1196
    }
 
1197
}
 
1198
 
 
1199
TEST_F(LibUAL, StartStopHelperObserver)
 
1200
{
 
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"};
 
1205
 
 
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));
 
1208
 
 
1209
    DbusTestDbusMockObject* obj =
 
1210
        dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);
 
1211
 
 
1212
    /* Basic start */
 
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'])"),
 
1216
        NULL);
 
1217
 
 
1218
    g_usleep(100000);
 
1219
    while (g_main_pending())
 
1220
    {
 
1221
        g_main_iteration(TRUE);
 
1222
    }
 
1223
 
 
1224
    ASSERT_EQ(start_data.count, 1);
 
1225
 
 
1226
    /* Basic stop */
 
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'])"),
 
1231
        NULL);
 
1232
 
 
1233
    g_usleep(100000);
 
1234
    while (g_main_pending())
 
1235
    {
 
1236
        g_main_iteration(TRUE);
 
1237
    }
 
1238
 
 
1239
    ASSERT_EQ(stop_data.count, 1);
 
1240
 
 
1241
    /* Remove */
 
1242
    ASSERT_TRUE(
 
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));
 
1245
}
 
1246
 
 
1247
gboolean datain(GIOChannel* source, GIOCondition cond, gpointer data)
 
1248
{
 
1249
    gsize* datacnt = static_cast<gsize*>(data);
 
1250
    gchar* str = NULL;
 
1251
    gsize len = 0;
 
1252
    GError* error = NULL;
 
1253
 
 
1254
    g_io_channel_read_line(source, &str, &len, NULL, &error);
 
1255
    g_free(str);
 
1256
 
 
1257
    if (error != NULL)
 
1258
    {
 
1259
        g_warning("Unable to read from channel: %s", error->message);
 
1260
        g_error_free(error);
 
1261
    }
 
1262
 
 
1263
    *datacnt += len;
 
1264
 
 
1265
    return TRUE;
 
1266
}
 
1267
 
 
1268
static void signal_increment(GDBusConnection* connection,
 
1269
                             const gchar* sender,
 
1270
                             const gchar* path,
 
1271
                             const gchar* interface,
 
1272
                             const gchar* signal,
 
1273
                             GVariant* params,
 
1274
                             gpointer user_data)
 
1275
{
 
1276
    guint* count = (guint*)user_data;
 
1277
    g_debug("Count incremented to: %d", *count + 1);
 
1278
    *count = *count + 1;
 
1279
}
 
1280
 
 
1281
TEST_F(LibUAL, PauseResume)
 
1282
{
 
1283
    g_setenv("UBUNTU_APP_LAUNCH_OOM_PROC_PATH", CMAKE_BINARY_DIR "/libual-proc", 1);
 
1284
 
 
1285
    /* Setup some spew */
 
1286
    GPid spewpid = 0;
 
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 */
 
1293
                                         NULL));                        /* error */
 
1294
 
 
1295
    gsize datacnt = 0;
 
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);
 
1299
 
 
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);
 
1304
    g_free(procdir);
 
1305
    ASSERT_TRUE(g_file_set_contents(oomadjfile, "0", -1, NULL));
 
1306
 
 
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);
 
1315
    g_free(pypids);
 
1316
 
 
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));
 
1320
 
 
1321
    /* Setup ZG Mock */
 
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);
 
1325
 
 
1326
    dbus_test_dbus_mock_object_add_method(zgmock, zgobj, "InsertEvents", G_VARIANT_TYPE("a(asaasay)"),
 
1327
                                          G_VARIANT_TYPE("au"), "ret = [ 0 ]", NULL);
 
1328
 
 
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));
 
1332
 
 
1333
    /* Give things a chance to start */
 
1334
    do
 
1335
    {
 
1336
        g_debug("Giving mocks a chance to start");
 
1337
        pause(200);
 
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);
 
1340
 
 
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);
 
1350
 
 
1351
    /* Test it */
 
1352
    EXPECT_NE(0, datacnt);
 
1353
    paused_count = 0;
 
1354
 
 
1355
    /* Pause the app */
 
1356
    EXPECT_TRUE(ubuntu_app_launch_pause_application("com.test.good_application_1.2.3"));
 
1357
 
 
1358
    pause(0);    /* Flush queued events */
 
1359
    datacnt = 0; /* clear it */
 
1360
 
 
1361
    pause(200);
 
1362
 
 
1363
    /* Check data coming out */
 
1364
    EXPECT_EQ(1, paused_count);
 
1365
    EXPECT_EQ(0, datacnt);
 
1366
 
 
1367
    /* Check to make sure we sent the event to ZG */
 
1368
    guint numcalls = 0;
 
1369
    const DbusTestDbusMockCall* calls =
 
1370
        dbus_test_dbus_mock_object_get_method_calls(zgmock, zgobj, "InsertEvents", &numcalls, NULL);
 
1371
 
 
1372
    EXPECT_NE(nullptr, calls);
 
1373
    EXPECT_EQ(1, numcalls);
 
1374
 
 
1375
    dbus_test_dbus_mock_object_clear_method_calls(zgmock, zgobj, NULL);
 
1376
 
 
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);
 
1382
    resumed_count = 0;
 
1383
 
 
1384
    /* Now Resume the App */
 
1385
    EXPECT_TRUE(ubuntu_app_launch_resume_application("com.test.good_application_1.2.3"));
 
1386
 
 
1387
    pause(200);
 
1388
 
 
1389
    EXPECT_NE(0, datacnt);
 
1390
    EXPECT_EQ(1, resumed_count);
 
1391
 
 
1392
    /* Check to make sure we sent the event to ZG */
 
1393
    numcalls = 0;
 
1394
    calls = dbus_test_dbus_mock_object_get_method_calls(zgmock, zgobj, "InsertEvents", &numcalls, NULL);
 
1395
 
 
1396
    EXPECT_NE(nullptr, calls);
 
1397
    EXPECT_EQ(1, numcalls);
 
1398
 
 
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);
 
1404
 
 
1405
    /* Clean up */
 
1406
    gchar* killstr = g_strdup_printf("kill -9 %d", spewpid);
 
1407
    ASSERT_TRUE(g_spawn_command_line_sync(killstr, NULL, NULL, NULL, NULL));
 
1408
    g_free(killstr);
 
1409
 
 
1410
    g_io_channel_unref(spewoutchan);
 
1411
 
 
1412
    g_spawn_command_line_sync("rm -rf " CMAKE_BINARY_DIR "/libual-proc", NULL, NULL, NULL, NULL);
 
1413
 
 
1414
    g_dbus_connection_signal_unsubscribe(bus, paused_signal);
 
1415
    g_dbus_connection_signal_unsubscribe(bus, resumed_signal);
 
1416
 
 
1417
    /* Kill ZG default instance :-( */
 
1418
    ZeitgeistLog* log = zeitgeist_log_get_default();
 
1419
    g_object_unref(log);
 
1420
    g_object_unref(log);
 
1421
 
 
1422
    g_free(oomadjfile);
 
1423
}
 
1424
 
 
1425
TEST_F(LibUAL, StartSessionHelper)
 
1426
{
 
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);
 
1431
 
 
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);
 
1437
 
 
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);
 
1442
 
 
1443
    helper->launch(msession);
 
1444
 
 
1445
    guint len = 0;
 
1446
    const DbusTestDbusMockCall* calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
 
1447
    EXPECT_NE(nullptr, calls);
 
1448
    EXPECT_EQ(1, len);
 
1449
 
 
1450
    EXPECT_STREQ("Start", calls->name);
 
1451
    EXPECT_EQ(2, g_variant_n_children(calls->params));
 
1452
 
 
1453
    GVariant* block = g_variant_get_child_value(calls->params, 1);
 
1454
    EXPECT_TRUE(g_variant_get_boolean(block));
 
1455
    g_variant_unref(block);
 
1456
 
 
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"));
 
1461
 
 
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 */
 
1468
 
 
1469
    g_variant_unref(env);
 
1470
 
 
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);
 
1476
 
 
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);
 
1481
 
 
1482
    /* Exec our tool */
 
1483
    std::promise<std::string> outputpromise;
 
1484
    std::thread t(
 
1485
        [&outputpromise]()
 
1486
        {
 
1487
            gchar* socketstdout = nullptr;
 
1488
            GError* error = nullptr;
 
1489
            g_unsetenv("G_MESSAGES_DEBUG");
 
1490
 
 
1491
            g_spawn_command_line_sync(SOCKET_DEMANGLER " " SOCKET_TOOL, &socketstdout, nullptr, nullptr, &error);
 
1492
 
 
1493
            if (error != nullptr)
 
1494
            {
 
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(""));
 
1498
            }
 
1499
            else
 
1500
            {
 
1501
                outputpromise.set_value(std::string(socketstdout));
 
1502
                g_free(socketstdout);
 
1503
            }
 
1504
        });
 
1505
    t.detach();
 
1506
 
 
1507
    auto outputfuture = outputpromise.get_future();
 
1508
    while (outputfuture.wait_for(std::chrono::milliseconds{1}) != std::future_status::ready)
 
1509
    {
 
1510
        pause();
 
1511
    }
 
1512
 
 
1513
    ASSERT_STREQ(filedata, outputfuture.get().c_str());
 
1514
 
 
1515
    ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
 
1516
 
 
1517
    return;
 
1518
}
 
1519
 
 
1520
TEST_F(LibUAL, SetExec)
 
1521
{
 
1522
    DbusTestDbusMockObject* obj =
 
1523
        dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);
 
1524
 
 
1525
    const char* exec = "lets exec this";
 
1526
 
 
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));
 
1530
 
 
1531
    guint len = 0;
 
1532
    const DbusTestDbusMockCall* calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "SetEnv", &len, NULL);
 
1533
    ASSERT_NE(nullptr, calls);
 
1534
    EXPECT_EQ(1, len);
 
1535
 
 
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);
 
1540
    g_free(appexecstr);
 
1541
 
 
1542
    ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
 
1543
 
 
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));
 
1547
 
 
1548
    calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "SetEnv", &len, NULL);
 
1549
    ASSERT_NE(nullptr, calls);
 
1550
    EXPECT_EQ(1, len);
 
1551
 
 
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);
 
1557
 
 
1558
    ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
 
1559
 
 
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"));
 
1563
 
 
1564
    calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "SetEnv", &len, NULL);
 
1565
    ASSERT_NE(nullptr, calls);
 
1566
    EXPECT_EQ(2, len);
 
1567
 
 
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);
 
1571
 
 
1572
    ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
 
1573
}
 
1574
 
 
1575
TEST_F(LibUAL, AppInfo)
 
1576
{
 
1577
    g_setenv("TEST_CLICK_DB", "click-db-dir", TRUE);
 
1578
    g_setenv("TEST_CLICK_USER", "test-user", TRUE);
 
1579
 
 
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);
 
1583
 
 
1584
    EXPECT_TRUE((bool)app->info());
 
1585
    EXPECT_EQ("Application", app->info()->name().value());
 
1586
 
 
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);
 
1590
 
 
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);
 
1594
 
 
1595
    auto info = libertine->info();
 
1596
    EXPECT_TRUE((bool)info);
 
1597
 
 
1598
    EXPECT_EQ("Test", info->name().value());
 
1599
}