~charlesk/indicator-session/use-gslice

« back to all changes in this revision

Viewing changes to tests/test-service.cc

  • Committer: Tarmac
  • Author(s): Charles Kerr, Lars Uebernickel
  • Date: 2013-07-12 14:58:31 UTC
  • mfrom: (384.2.112 ng-login1)
  • Revision ID: tarmac-20130712145831-n2bqrachsd9qa90n
This is the GMenu, login1 version of indicator-session.

This resubmission removes the prerequisite branch because the entire diff is contained in this ng-login1 branch.

Approved by PS Jenkins bot.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
with this program.  If not, see <http://www.gnu.org/licenses/>.
18
18
*/
19
19
 
20
 
#include <glib-object.h>
21
 
#include <gio/gio.h>
22
 
#include <glib.h>
23
 
 
24
 
#include <gtest/gtest.h>
25
 
 
26
 
#include "shared-names.h"
 
20
#include "gtest-dbus-fixture.h"
 
21
#include "service.h"
 
22
#include "backend-mock.h"
 
23
#include "backend-mock-users.h"
 
24
#include "backend-mock-guest.h"
 
25
#include "backend-mock-actions.h"
27
26
 
28
27
/***
29
28
****
30
29
***/
31
30
 
32
 
#define INDICATOR_SERVICE_OBJECT_PATH "/org/ayatana/indicator/service"
33
 
#define INDICATOR_SERVICE_INTERFACE_NAME "org.ayatana.indicator.service"
34
 
 
35
 
class ClientTest : public ::testing::Test
36
 
{
37
 
  protected:
38
 
 
39
 
    GTestDBus * test_dbus;
40
 
    GDBusConnection * session_bus;
41
 
    GMainLoop * main_loop;
42
 
 
43
 
    virtual void SetUp()
44
 
    {
45
 
      test_dbus = NULL;
46
 
      session_bus = NULL;
47
 
      main_loop = NULL;
48
 
 
49
 
      static bool first_run = true;
50
 
      if (first_run)
51
 
        {
52
 
          g_setenv ("INDICATOR_SERVICE_SHUTDOWN_TIMEOUT", "1000", TRUE);
53
 
          g_unsetenv ("INDICATOR_ALLOW_NO_WATCHERS");
54
 
          g_unsetenv ("INDICATOR_SERVICE_REPLACE_MODE");
55
 
          g_setenv ("GSETTINGS_SCHEMA_DIR", SCHEMA_DIR, TRUE);
56
 
          g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
57
 
          first_run = false;
58
 
        }
59
 
 
60
 
      main_loop = g_main_loop_new (NULL, FALSE);
61
 
      // pull up a test dbus that's pointed at our test .service file
62
 
      test_dbus = g_test_dbus_new (G_TEST_DBUS_NONE);
63
 
      g_debug (G_STRLOC" service dir path is \"%s\"", INDICATOR_SERVICE_DIR);
64
 
      g_test_dbus_add_service_dir (test_dbus, INDICATOR_SERVICE_DIR);
65
 
 
66
 
      // allow the service to exist w/o a sync indicator
67
 
      g_setenv ("INDICATOR_ALLOW_NO_WATCHERS", "1", TRUE);
68
 
 
69
 
      g_test_dbus_up (test_dbus);
70
 
      g_debug (G_STRLOC" this test bus' address is \"%s\"", g_test_dbus_get_bus_address(test_dbus));
71
 
      session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
72
 
      g_debug (G_STRLOC" the dbus connection %p unique name is \"%s\"", session_bus, g_dbus_connection_get_unique_name(session_bus));
73
 
      g_debug (G_STRLOC" the dbus connection %p refcount is %d", session_bus, G_OBJECT(session_bus)->ref_count);
74
 
    }
75
 
 
76
 
    // undo SetUp
77
 
    virtual void TearDown()
78
 
    {
79
 
      g_clear_object (&session_bus);
80
 
      g_debug (G_STRLOC" tearing down the bus");
81
 
      g_test_dbus_down (test_dbus);
82
 
      g_clear_object (&test_dbus);
83
 
      g_clear_pointer (&main_loop, g_main_loop_unref);
 
31
#if 0
 
32
namespace
 
33
{
 
34
  void
 
35
  dump_menu_model (GMenuModel * model, int depth)
 
36
  {
 
37
    GString * indent = g_string_new_len ("                                                  ", (depth*4));
 
38
    const int n = g_menu_model_get_n_items (model);
 
39
    g_message ("%s depth[%d] menu model[%p] has %d items", indent->str, depth, (void*)model, n);
 
40
 
 
41
    for (int i=0; i<n; ++i)
 
42
      {
 
43
        const char * name;
 
44
        GMenuModel * link_value;
 
45
        GVariant * attribute_value;
 
46
 
 
47
        GMenuAttributeIter * attribute_iter = g_menu_model_iterate_item_attributes (model, i);
 
48
        while (g_menu_attribute_iter_get_next (attribute_iter, &name, &attribute_value))
 
49
          {
 
50
            char * str = g_variant_print (attribute_value, TRUE);
 
51
            g_message ("%s depth[%d] menu model[%p] item[%d] attribute key[%s] value[%s]", indent->str, depth, (void*)model, i, name, str);
 
52
            g_free (str);
 
53
            g_variant_unref (attribute_value);
 
54
          }
 
55
        g_clear_object (&attribute_iter);
 
56
 
 
57
        GMenuLinkIter * link_iter = g_menu_model_iterate_item_links (model, i);
 
58
        while (g_menu_link_iter_get_next (link_iter, &name, &link_value))
 
59
          {
 
60
            g_message ("%s depth[%d] menu model[%p] item[%d] attribute key[%s] model[%p]", indent->str, depth, (void*)model, i, name, (void*)link_value);
 
61
            dump_menu_model (link_value, depth+1);
 
62
            g_object_unref (link_value);
 
63
          }
 
64
        g_clear_object (&link_iter);
 
65
      }
 
66
    g_string_free (indent, TRUE);
 
67
  }
 
68
}
 
69
#endif
 
70
 
 
71
 
 
72
/* cppcheck-suppress noConstructor */
 
73
class ServiceTest: public GTestDBusFixture
 
74
{
 
75
    typedef GTestDBusFixture super;
 
76
 
 
77
    enum { TIME_LIMIT_SEC = 10 };
 
78
 
 
79
  private:
 
80
 
 
81
    static void on_name_appeared (GDBusConnection * connection   G_GNUC_UNUSED,
 
82
                                  const gchar     * name         G_GNUC_UNUSED,
 
83
                                  const gchar     * name_owner   G_GNUC_UNUSED,
 
84
                                  gpointer          gself)
 
85
    {
 
86
      g_main_loop_quit (static_cast<ServiceTest*>(gself)->loop);
 
87
    }
 
88
 
 
89
    GSList * menu_references;
 
90
 
 
91
    bool any_item_changed;
 
92
 
 
93
    static void on_items_changed (GMenuModel  * model      G_GNUC_UNUSED,
 
94
                                  gint          position   G_GNUC_UNUSED,
 
95
                                  gint          removed    G_GNUC_UNUSED,
 
96
                                  gint          added      G_GNUC_UNUSED,
 
97
                                  gpointer      any_item_changed)
 
98
    {
 
99
      *((gboolean*)any_item_changed) = true;
 
100
    }
 
101
 
 
102
  protected:
 
103
 
 
104
    void activate_subtree (GMenuModel * model)
 
105
    {
 
106
      // query the GDBusMenuModel for information to activate it
 
107
      int n = g_menu_model_get_n_items (model);
 
108
      if (!n)
 
109
        {
 
110
          // give the model a moment to populate its info
 
111
          wait_msec (100);
 
112
          n = g_menu_model_get_n_items (model);
 
113
        }
 
114
 
 
115
      // keep a ref so that it stays activated
 
116
      menu_references = g_slist_prepend (menu_references, g_object_ref(model));
 
117
 
 
118
      g_signal_connect (model, "items-changed", G_CALLBACK(on_items_changed), &any_item_changed);
 
119
 
 
120
      // recurse
 
121
      for (int i=0; i<n; ++i)
 
122
        {
 
123
          GMenuModel * link;
 
124
          GMenuLinkIter * iter = g_menu_model_iterate_item_links (model, i);
 
125
          while (g_menu_link_iter_get_next (iter, NULL, &link))
 
126
            {
 
127
              activate_subtree (link);
 
128
              g_object_unref (link);
 
129
            }
 
130
          g_clear_object (&iter);
 
131
        }
 
132
    }
 
133
 
 
134
    void sync_menu (void)
 
135
    {
 
136
      g_slist_free_full (menu_references, (GDestroyNotify)g_object_unref);
 
137
      menu_references = NULL;
 
138
      activate_subtree (G_MENU_MODEL (menu_model));
 
139
    }
 
140
 
 
141
    GDBusMenuModel * menu_model;
 
142
    GDBusActionGroup * action_group;
 
143
    IndicatorSessionService * service;
 
144
    GTimer * timer;
 
145
    GSettings * indicator_settings;
 
146
 
 
147
    virtual void SetUp ()
 
148
    {
 
149
      super :: SetUp ();
 
150
 
 
151
      menu_references = NULL;
 
152
      any_item_changed = NULL;
 
153
 
 
154
      timer = g_timer_new ();
 
155
      mock_settings = g_settings_new ("com.canonical.indicator.session.backendmock");
 
156
      mock_actions = indicator_session_actions_mock_new ();
 
157
      mock_users = indicator_session_users_mock_new ();
 
158
      mock_guest = indicator_session_guest_mock_new ();
 
159
      indicator_settings = g_settings_new ("com.canonical.indicator.session");
 
160
 
 
161
      // Start an IndicatorSessionService and wait for it to appear on the bus.
 
162
      // This way our calls to g_dbus_*_get() in the next paragraph won't activate
 
163
      // a second copy of the service...
 
164
      service = indicator_session_service_new ();
 
165
 
 
166
      // wait for the service to show up on the bus
 
167
      const guint watch_id = g_bus_watch_name_on_connection (conn,
 
168
                                                             "com.canonical.indicator.session",
 
169
                                                             G_BUS_NAME_WATCHER_FLAGS_NONE,
 
170
                                                             on_name_appeared, // quits the loop
 
171
                                                             NULL, this, NULL);
 
172
      const guint timer_id = g_timeout_add_seconds (TIME_LIMIT_SEC, (GSourceFunc)g_main_loop_quit, loop);
 
173
      g_main_loop_run (loop);
 
174
      g_source_remove (timer_id);
 
175
      g_bus_unwatch_name (watch_id);
 
176
      ASSERT_FALSE (times_up());
 
177
 
 
178
      // get the actions & menus that the service exported.
 
179
      action_group = g_dbus_action_group_get (conn,
 
180
                                              "com.canonical.indicator.session",
 
181
                                              "/com/canonical/indicator/session");
 
182
      menu_model = g_dbus_menu_model_get (conn,
 
183
                                          "com.canonical.indicator.session",
 
184
                                          "/com/canonical/indicator/session/desktop");
 
185
      // the actions are added asynchronously, so wait for the actions
 
186
      if (!g_action_group_has_action (G_ACTION_GROUP(action_group), "about"))
 
187
        wait_for_signal (action_group, "action-added");
 
188
      // activate all the groups in the menu so it'll be ready when we need it
 
189
      g_signal_connect (menu_model, "items-changed", G_CALLBACK(on_items_changed), &any_item_changed);
 
190
      sync_menu ();
 
191
    }
 
192
 
 
193
    virtual void TearDown ()
 
194
    {
 
195
      g_clear_pointer (&timer, g_timer_destroy);
 
196
 
 
197
      g_slist_free_full (menu_references, (GDestroyNotify)g_object_unref);
 
198
      menu_references = NULL;
 
199
      g_clear_object (&menu_model);
 
200
 
 
201
      g_clear_object (&action_group);
 
202
      g_clear_object (&mock_settings);
 
203
      g_clear_object (&indicator_settings);
 
204
      g_clear_object (&service);
 
205
      g_clear_object (&mock_actions);
 
206
      g_clear_object (&mock_users);
 
207
      g_clear_object (&mock_guest);
 
208
      wait_msec (100);
 
209
 
 
210
      super :: TearDown ();
 
211
    }
 
212
 
 
213
  protected:
 
214
 
 
215
    bool times_up () const
 
216
    {
 
217
      return g_timer_elapsed (timer, NULL) >= TIME_LIMIT_SEC;
 
218
    }
 
219
 
 
220
    void wait_for_has_action (const char * name)
 
221
    {
 
222
      while (!g_action_group_has_action (G_ACTION_GROUP(action_group), name) && !times_up())
 
223
        wait_msec (50);
 
224
 
 
225
      ASSERT_FALSE (times_up());
 
226
      ASSERT_TRUE (g_action_group_has_action (G_ACTION_GROUP(action_group), name));
 
227
    }
 
228
 
 
229
    void wait_for_menu_resync (void)
 
230
    {
 
231
      any_item_changed = false;
 
232
      while (!times_up() && !any_item_changed)
 
233
        wait_msec (50);
 
234
      sync_menu ();
 
235
    }
 
236
 
 
237
  protected:
 
238
 
 
239
    void check_last_command_is (const char * expected)
 
240
    {
 
241
      char * str = g_settings_get_string (mock_settings, "last-command");
 
242
      ASSERT_STREQ (expected, str);
 
243
      g_free (str);
 
244
    }
 
245
 
 
246
    void test_simple_action (const char * action_name)
 
247
    {
 
248
      wait_for_has_action (action_name);
 
249
 
 
250
      g_action_group_activate_action (G_ACTION_GROUP (action_group), action_name, NULL);
 
251
      wait_for_signal (mock_settings, "changed::last-command");
 
252
      check_last_command_is (action_name);
 
253
    }
 
254
 
 
255
  protected:
 
256
 
 
257
    bool find_menu_item_for_action (const char * action_key, GMenuModel ** setme, int * item_index)
 
258
    {
 
259
      bool success = false;
 
260
 
 
261
      for (GSList * l=menu_references; !success && (l!=NULL); l=l->next)
 
262
        {
 
263
          GMenuModel * mm = G_MENU_MODEL (l->data);
 
264
          const int n = g_menu_model_get_n_items (mm);
 
265
 
 
266
          for (int i=0; !success && i<n; ++i)
 
267
            {
 
268
              char * action = NULL;
 
269
              if (!g_menu_model_get_item_attribute (mm, i, G_MENU_ATTRIBUTE_ACTION, "s", &action))
 
270
                continue;
 
271
 
 
272
              if ((success = !g_strcmp0 (action, action_key)))
 
273
                {
 
274
                  if (setme != NULL)
 
275
                    *setme = G_MENU_MODEL (g_object_ref (G_OBJECT(mm)));
 
276
 
 
277
                  if (item_index != NULL)
 
278
                    *item_index = i;
 
279
                }
 
280
 
 
281
              g_free (action);
 
282
            }
 
283
        }
 
284
 
 
285
      return success;
 
286
    }
 
287
 
 
288
    bool action_menuitem_exists (const char * action_name)
 
289
    {
 
290
      bool found;
 
291
      GMenuModel * model = 0;
 
292
      int pos = -1;
 
293
 
 
294
      if ((found = find_menu_item_for_action (action_name, &model, &pos)))
 
295
        g_object_unref (G_OBJECT(model));
 
296
 
 
297
      return found;
 
298
    }
 
299
 
 
300
    bool action_menuitem_label_is_ellipsized (const char * action_name)
 
301
    {
 
302
      int pos = -1;
 
303
      GMenuModel * model = 0;
 
304
      bool ellipsized = false;
 
305
      char * label = NULL;
 
306
 
 
307
      if (find_menu_item_for_action (action_name, &model, &pos))
 
308
        {
 
309
          g_menu_model_get_item_attribute (model, pos, G_MENU_ATTRIBUTE_LABEL, "s", &label);
 
310
          g_object_unref (G_OBJECT(model));
 
311
        }
 
312
 
 
313
      ellipsized = (label != NULL) && g_str_has_suffix (label, "\342\200\246");
 
314
      g_free (label);
 
315
      return ellipsized;
 
316
    }
 
317
 
 
318
    void check_header (const char * expected_label, const char * expected_icon, const char * expected_a11y)
 
319
    {
 
320
       GVariant * variant;
 
321
       const gchar * label = NULL;
 
322
       const gchar * icon = NULL;
 
323
       const gchar * a11y = NULL;
 
324
       gboolean visible;
 
325
 
 
326
      variant = g_action_group_get_action_state (G_ACTION_GROUP(action_group), "_header");
 
327
      g_variant_get (variant, "(&s&s&sb)", &label, &icon, &a11y, &visible);
 
328
 
 
329
      if (expected_label != NULL)
 
330
        ASSERT_STREQ (expected_label, label);
 
331
 
 
332
      if (expected_icon != NULL)
 
333
        ASSERT_STREQ (expected_icon, icon);
 
334
 
 
335
      if (expected_a11y != NULL)
 
336
        ASSERT_STREQ (expected_a11y, a11y);
 
337
 
 
338
      // the session menu is always visible...
 
339
      ASSERT_TRUE (visible);
 
340
 
 
341
      g_variant_unref (variant);
 
342
    }
 
343
 
 
344
    void check_label (const char * expected_label, GMenuModel * model, int pos)
 
345
    {
 
346
      char * label = NULL;
 
347
      ASSERT_TRUE (g_menu_model_get_item_attribute (model, pos, G_MENU_ATTRIBUTE_LABEL, "s", &label));
 
348
      ASSERT_STREQ (expected_label, label);
 
349
      g_free (label);
84
350
    }
85
351
};
86
352
 
88
354
****
89
355
***/
90
356
 
 
357
#if 0
 
358
TEST_F (ServiceTest, HelloWorld)
 
359
{
 
360
  ASSERT_TRUE (true);
 
361
}
 
362
#endif
 
363
 
 
364
TEST_F (ServiceTest, About)
 
365
{
 
366
  test_simple_action ("about");
 
367
}
 
368
 
 
369
TEST_F (ServiceTest, Help)
 
370
{
 
371
  test_simple_action ("help");
 
372
}
 
373
 
 
374
TEST_F (ServiceTest, Hibernate)
 
375
{
 
376
  test_simple_action ("hibernate");
 
377
}
 
378
 
 
379
TEST_F (ServiceTest, Settings)
 
380
{
 
381
  test_simple_action ("settings");
 
382
}
 
383
 
 
384
TEST_F (ServiceTest, Logout)
 
385
{
 
386
  test_simple_action ("logout");
 
387
}
 
388
 
 
389
TEST_F (ServiceTest, PowerOff)
 
390
{
 
391
  test_simple_action ("power-off");
 
392
}
 
393
 
 
394
TEST_F (ServiceTest, Reboot)
 
395
{
 
396
  test_simple_action ("reboot");
 
397
}
 
398
 
 
399
TEST_F (ServiceTest, SwitchToScreensaver)
 
400
{
 
401
  test_simple_action ("switch-to-screensaver");
 
402
}
 
403
 
 
404
TEST_F (ServiceTest, SwitchToGuest)
 
405
{
 
406
  test_simple_action ("switch-to-guest");
 
407
}
 
408
 
 
409
TEST_F (ServiceTest, SwitchToGreeter)
 
410
{
 
411
  test_simple_action ("switch-to-greeter");
 
412
}
 
413
 
 
414
TEST_F (ServiceTest, Suspend)
 
415
{
 
416
  test_simple_action ("suspend");
 
417
}
 
418
 
 
419
#if 0
 
420
namespace
 
421
{
 
422
  gboolean
 
423
  find_menu_item_for_action (GMenuModel * top, const char * action_key, GMenuModel ** setme, int * item_index)
 
424
  {
 
425
    gboolean success = FALSE;
 
426
    const int n = g_menu_model_get_n_items (top);
 
427
 
 
428
    for (int i=0; !success && i<n; ++i)
 
429
      {
 
430
        char * action = NULL;
 
431
        if (g_menu_model_get_item_attribute (top, i, G_MENU_ATTRIBUTE_ACTION, "s", &action))
 
432
          {
 
433
            if ((success = !g_strcmp0 (action, action_key)))
 
434
              {
 
435
                *setme = G_MENU_MODEL (g_object_ref (G_OBJECT(top)));
 
436
                *item_index = i;
 
437
              }
 
438
 
 
439
            g_free (action);
 
440
          }
 
441
 
 
442
        const char * name = NULL;
 
443
        GMenuModel * link_value = NULL;
 
444
        GMenuLinkIter * link_iter = g_menu_model_iterate_item_links (top, i);
 
445
        while (!success && g_menu_link_iter_get_next (link_iter, &name, &link_value))
 
446
          {
 
447
            success = find_menu_item_for_action (link_value, action_key, setme, item_index);
 
448
            g_object_unref (link_value);
 
449
          }
 
450
        g_clear_object (&link_iter);
 
451
      }
 
452
 
 
453
    return success;
 
454
  }
 
455
 
 
456
  gchar *
 
457
  get_menu_label_for_action (GMenuModel * top, const char * action)
 
458
  {
 
459
    int pos;
 
460
    GMenuModel * model;
 
461
    gchar * label = NULL;
 
462
 
 
463
    if (find_menu_item_for_action (top, action, &model, &pos))
 
464
      {
 
465
        g_menu_model_get_item_attribute (model, pos, G_MENU_ATTRIBUTE_LABEL, "s", &label);
 
466
        g_object_unref (G_OBJECT(model));
 
467
      }
 
468
 
 
469
    return label;
 
470
  }
 
471
 
 
472
  gboolean str_is_ellipsized (const char * str)
 
473
  {
 
474
    g_assert (str != NULL);
 
475
    return g_str_has_suffix (str, "\342\200\246");
 
476
  }
 
477
}
 
478
#endif
 
479
 
 
480
TEST_F (ServiceTest, ConfirmationDisabledByBackend)
 
481
{
 
482
  const char * const confirm_supported_key = "can-prompt";
 
483
  const char * const confirm_disabled_key = "suppress-logout-restart-shutdown";
 
484
 
 
485
  bool confirm_supported = g_settings_get_boolean (mock_settings, confirm_supported_key);
 
486
  bool confirm_disabled = g_settings_get_boolean (indicator_settings, confirm_disabled_key);
 
487
  bool confirm = confirm_supported && !confirm_disabled;
 
488
 
 
489
  // confirm that the ellipsis are correct
 
490
  ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.switch-to-greeter"));
 
491
  ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.logout"));
 
492
  if (action_menuitem_exists ("indicator.reboot"))
 
493
    ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.reboot"));
 
494
  ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.power-off"));
 
495
 
 
496
  // now toggle the can-prompt flag
 
497
  confirm_supported = !confirm_supported;
 
498
  g_settings_set_boolean (mock_settings, confirm_supported_key, confirm_supported);
 
499
  confirm = confirm_supported && !confirm_disabled;
 
500
 
 
501
  wait_for_menu_resync ();
 
502
 
 
503
  // confirm that the ellipsis are correct
 
504
  ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.switch-to-greeter"));
 
505
  ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.logout"));
 
506
  if (action_menuitem_exists ("indicator.reboot"))
 
507
    ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.reboot"));
 
508
  ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.power-off"));
 
509
 
 
510
  // cleanup
 
511
  g_settings_reset (mock_settings, confirm_supported_key);
 
512
}
 
513
 
 
514
TEST_F (ServiceTest, ConfirmationDisabledByUser)
 
515
{
 
516
  const char * const confirm_supported_key = "can-prompt";
 
517
  const char * const confirm_disabled_key = "suppress-logout-restart-shutdown";
 
518
 
 
519
  bool confirm_supported = g_settings_get_boolean (mock_settings, confirm_supported_key);
 
520
  bool confirm_disabled = g_settings_get_boolean (indicator_settings, confirm_disabled_key);
 
521
  bool confirm = confirm_supported && !confirm_disabled;
 
522
 
 
523
  // confirm that the ellipsis are correct
 
524
  ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.switch-to-greeter"));
 
525
  ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.logout"));
 
526
  if (action_menuitem_exists ("indicator.reboot"))
 
527
    ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.reboot"));
 
528
  ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.power-off"));
 
529
 
 
530
  // now toggle the can-prompt flag
 
531
  confirm_disabled = !confirm_disabled;
 
532
  g_settings_set_boolean (indicator_settings, confirm_disabled_key, confirm_disabled);
 
533
  confirm = confirm_supported && !confirm_disabled;
 
534
 
 
535
  wait_for_menu_resync ();
 
536
 
 
537
  // confirm that the ellipsis are correct
 
538
  ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.switch-to-greeter"));
 
539
  ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.logout"));
 
540
  if (action_menuitem_exists ("indicator.reboot"))
 
541
    ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.reboot"));
 
542
  ASSERT_EQ (confirm, action_menuitem_label_is_ellipsized ("indicator.power-off"));
 
543
 
 
544
  // cleanup
 
545
  g_settings_reset (indicator_settings, confirm_disabled_key);
 
546
}
 
547
 
91
548
/**
92
 
 * This is a basic test to see if we can launch indicator-session-service
93
 
 * and call its "GetUserRealName" method. The test succeeds if we can launch
94
 
 * the service, call the method, and get response that equals g_get_real_name().
95
 
 *
96
 
 * (You may be wondering why GetUserRealName() exists at all, instead of clients
97
 
 * using g_get_real_name(). It's because the former updates itslef when the user
98
 
 * edits his real name, while the latter returns its cached copy of the old name.)
 
549
 * Check that the default menu has items for each of these actions
99
550
 */
100
 
TEST_F (ClientTest, TestCanStartService)
101
 
{
102
 
  GError * error;
103
 
  GVariant * result;
104
 
  const gchar * name;
105
 
 
106
 
  // call GetUserRealName(), which as a side effect should activate
107
 
  // indicator-session-service via the .service file in the tests/ directory
108
 
  error = NULL;
109
 
  result = g_dbus_connection_call_sync (session_bus,
110
 
                                        INDICATOR_SESSION_DBUS_NAME,
111
 
                                        INDICATOR_SESSION_SERVICE_DBUS_OBJECT,
112
 
                                        INDICATOR_SESSION_SERVICE_DBUS_IFACE,
113
 
                                        "GetUserRealName",
114
 
                                        NULL,
115
 
                                        G_VARIANT_TYPE("(s)"),
116
 
                                        G_DBUS_CALL_FLAGS_NONE,
117
 
                                        -1,
118
 
                                        NULL,
119
 
                                        &error);
120
 
 
121
 
  EXPECT_TRUE (error == NULL);
122
 
  ASSERT_TRUE (result != NULL);
123
 
 
124
 
  if (error != NULL)
125
 
    {
126
 
      g_warning ("GetUserRealName failed: %s", error->message);
127
 
      g_clear_error (&error);
128
 
    }
129
 
 
130
 
  name = NULL;
131
 
  g_variant_get (result, "(&s)", &name);
132
 
  ASSERT_STREQ (g_get_real_name(), name);
133
 
  g_clear_pointer (&result, g_variant_unref);
134
 
 
135
 
  // call IndicatorService's Shutdown() method for a clean exit
136
 
  result = g_dbus_connection_call_sync (session_bus,
137
 
                                        INDICATOR_SESSION_DBUS_NAME,
138
 
                                        "/org/ayatana/indicator/service",
139
 
                                        "org.ayatana.indicator.service",
140
 
                                        "Shutdown", NULL,
141
 
                                        NULL,
142
 
                                        G_DBUS_CALL_FLAGS_NONE,
143
 
                                        -1, NULL, NULL);
144
 
  g_clear_pointer (&result, g_variant_unref);
 
551
TEST_F (ServiceTest, DefaultMenuItems)
 
552
{
 
553
  ASSERT_TRUE (find_menu_item_for_action ("indicator.about", NULL, NULL));
 
554
  ASSERT_TRUE (find_menu_item_for_action ("indicator.help", NULL, NULL));
 
555
  ASSERT_TRUE (find_menu_item_for_action ("indicator.settings", NULL, NULL));
 
556
  ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-greeter", NULL, NULL));
 
557
  ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-guest", NULL, NULL));
 
558
  ASSERT_TRUE (find_menu_item_for_action ("indicator.logout", NULL, NULL));
 
559
  ASSERT_TRUE (find_menu_item_for_action ("indicator.suspend", NULL, NULL));
 
560
  ASSERT_TRUE (find_menu_item_for_action ("indicator.hibernate", NULL, NULL));
 
561
  ASSERT_TRUE (find_menu_item_for_action ("indicator.power-off", NULL, NULL));
 
562
}
 
563
 
 
564
TEST_F (ServiceTest, OnlineAccountError)
 
565
{
 
566
  bool err;
 
567
  int pos = -1;
 
568
  GMenuModel * model = 0;
 
569
  const char * const error_key = "has-online-account-error";
 
570
 
 
571
  // check the initial default header state
 
572
  check_header ("", "system-devices-panel", "System");
 
573
 
 
574
  // check that the menuitems' existence matches the error flag
 
575
  err = g_settings_get_boolean (mock_settings, error_key);
 
576
  ASSERT_FALSE (err);
 
577
  ASSERT_EQ (err, find_menu_item_for_action ("indicator.online-accounts", &model, &pos));
 
578
  g_clear_object (&model);
 
579
 
 
580
  // now toggle the error flag
 
581
  err = !err;
 
582
  g_settings_set_boolean (mock_settings, error_key, err);
 
583
 
 
584
  // wait for the _header action and error menuitem to update
 
585
  wait_for_menu_resync ();
 
586
 
 
587
  // check that the menuitems' existence matches the error flag
 
588
  ASSERT_TRUE (g_settings_get_boolean (mock_settings, error_key));
 
589
  ASSERT_TRUE (find_menu_item_for_action ("indicator.online-accounts", &model, &pos));
 
590
  g_clear_object (&model);
 
591
 
 
592
  // check that the service has a corresponding action
 
593
  ASSERT_TRUE (g_action_group_has_action (G_ACTION_GROUP(action_group), "online-accounts"));
 
594
  ASSERT_TRUE (g_action_group_get_action_enabled (G_ACTION_GROUP(action_group), "online-accounts"));
 
595
 
 
596
  // confirm that activating the action is handled by the service
 
597
  g_action_group_activate_action (G_ACTION_GROUP(action_group), "online-accounts", NULL);
 
598
  wait_for_signal (mock_settings, "changed::last-command");
 
599
  check_last_command_is ("online-accounts");
 
600
 
 
601
  // check that the header's icon and a11y adjusted to the error state
 
602
  check_header ("", "system-devices-panel-alert", "System (Attention Required)");
 
603
 
 
604
  // cleanup
 
605
  g_settings_reset (mock_settings, error_key);
 
606
}
 
607
 
 
608
namespace
 
609
{
 
610
  gboolean set_live_session_to_true (gpointer unused G_GNUC_UNUSED)
 
611
  {
 
612
    const char * const live_session_key = "is-live-session";
 
613
    g_settings_set_boolean (mock_settings, live_session_key, true);
 
614
    return G_SOURCE_REMOVE;
 
615
  }
 
616
}
 
617
 
 
618
TEST_F (ServiceTest, LiveSession)
 
619
{
 
620
  gboolean b;
 
621
  const char * const live_session_key = "is-live-session";
 
622
 
 
623
  // default BackendMock is not a live session
 
624
  ASSERT_FALSE (g_settings_get_boolean (mock_settings, live_session_key));
 
625
  g_object_get (mock_users, INDICATOR_SESSION_USERS_PROP_IS_LIVE_SESSION, &b, NULL);
 
626
  ASSERT_FALSE (b);
 
627
 
 
628
  // confirm that we can see live sessions
 
629
  g_idle_add (set_live_session_to_true, NULL);
 
630
  wait_for_signal (mock_users, "notify::" INDICATOR_SESSION_USERS_PROP_IS_LIVE_SESSION);
 
631
  ASSERT_TRUE (g_settings_get_boolean (mock_settings, live_session_key));
 
632
  wait_msec (50);
 
633
  g_object_get (mock_users, INDICATOR_SESSION_USERS_PROP_IS_LIVE_SESSION, &b, NULL);
 
634
  ASSERT_TRUE (b);
 
635
 
 
636
  // cleanup
 
637
  g_settings_reset (mock_settings, live_session_key);
 
638
}
 
639
 
 
640
 
 
641
TEST_F (ServiceTest, User)
 
642
{
 
643
  const char * const error_key = "has-online-account-error";
 
644
  const char * const show_name_key = "show-real-name-on-panel";
 
645
 
 
646
  struct {
 
647
    guint uid;
 
648
    guint64 login_frequency;
 
649
    const gchar * user_name;
 
650
    const gchar * real_name;
 
651
  } account_info[] = {
 
652
    { 101, 134, "whartnell",  "First Doctor"    },
 
653
    { 102, 119, "ptroughton", "Second Doctor"   },
 
654
    { 103, 128, "jpertwee",   "Third Doctor"    },
 
655
    { 104, 172, "tbaker",     "Fourth Doctor"   },
 
656
    { 105,  69, "pdavison",   "Fifth Doctor"    },
 
657
    { 106,  31, "cbaker",     "Sixth Doctor"    },
 
658
    { 107,  42, "smccoy",     "Seventh Doctor"  },
 
659
    { 108,   1, "pmcgann",    "Eigth Doctor"    },
 
660
    { 109,  13, "ceccleston", "Ninth Doctor"    },
 
661
    { 110,  47, "dtennant",   "Tenth Doctor"    },
 
662
    { 111,  34, "msmith",     "Eleventh Doctor" },
 
663
    { 201,   1, "rhurndall",  "First Doctor"    }
 
664
  };
 
665
 
 
666
  // Find the switcher menu model.
 
667
  // In BackendMock's default setup, it will only two menuitems: greeter & guest
 
668
  int pos = 0;
 
669
  GMenuModel * switch_menu = 0;
 
670
  ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-greeter", &switch_menu, &pos));
 
671
  ASSERT_EQ (0, pos);
 
672
  ASSERT_EQ (2, g_menu_model_get_n_items (switch_menu));
 
673
  g_clear_object (&switch_menu);
 
674
 
 
675
  // now add some users
 
676
  IndicatorSessionUser * users[12];
 
677
  for (int i=0; i<12; ++i)
 
678
    users[i] = 0;
 
679
  for (int i=0; i<5; ++i)
 
680
    {
 
681
      IndicatorSessionUser * u = g_new0 (IndicatorSessionUser, 1);
 
682
      u->is_current_user = false;
 
683
      u->is_logged_in = false;
 
684
      u->uid = account_info[i].uid;
 
685
      u->login_frequency = account_info[i].login_frequency;
 
686
      u->user_name = g_strdup (account_info[i].user_name);
 
687
      u->real_name = g_strdup (account_info[i].real_name);
 
688
      indicator_session_users_mock_add_user (INDICATOR_SESSION_USERS_MOCK(mock_users), u);
 
689
      users[i] = u;
 
690
    }
 
691
 
 
692
  wait_for_menu_resync ();
 
693
 
 
694
  // now there should be 7 menuitems: greeter + guest + the five doctors
 
695
  ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-greeter", &switch_menu, &pos));
 
696
  ASSERT_EQ (0, pos);
 
697
  ASSERT_EQ (7, g_menu_model_get_n_items (switch_menu));
 
698
  // confirm that the doctor names are sorted
 
699
  check_label ("Fifth Doctor", switch_menu, 2);
 
700
  check_label ("First Doctor", switch_menu, 3);
 
701
  check_label ("Fourth Doctor", switch_menu, 4);
 
702
  check_label ("Second Doctor", switch_menu, 5);
 
703
  check_label ("Third Doctor", switch_menu, 6);
 
704
  g_clear_object (&switch_menu);
 
705
 
 
706
  // now remove a couple of 'em
 
707
  indicator_session_users_mock_remove_user (INDICATOR_SESSION_USERS_MOCK(mock_users), account_info[3].uid);
 
708
  indicator_session_users_mock_remove_user (INDICATOR_SESSION_USERS_MOCK(mock_users), account_info[4].uid);
 
709
 
 
710
  wait_for_menu_resync ();
 
711
 
 
712
  // now there should be 5 menuitems: greeter + guest + the three doctors
 
713
  ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-greeter", &switch_menu, &pos));
 
714
  ASSERT_EQ (0, pos);
 
715
  ASSERT_EQ (5, g_menu_model_get_n_items (switch_menu));
 
716
  // confirm that the doctor names are sorted
 
717
  check_label ("First Doctor", switch_menu, 2);
 
718
  check_label ("Second Doctor", switch_menu, 3);
 
719
  check_label ("Third Doctor", switch_menu, 4);
 
720
  g_clear_object (&switch_menu);
 
721
 
 
722
  // now let's have the third one be the current user
 
723
  users[2]->is_current_user = true;
 
724
  users[2]->is_logged_in = true;
 
725
  indicator_session_users_changed (mock_users, users[2]->uid);
 
726
 
 
727
  wait_for_menu_resync ();
 
728
 
 
729
  // now there should be 5 menuitems: greeter + guest + the three doctors
 
730
  ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-greeter", &switch_menu, &pos));
 
731
  ASSERT_EQ (0, pos);
 
732
  ASSERT_EQ (5, g_menu_model_get_n_items (switch_menu));
 
733
  g_clear_object (&switch_menu);
 
734
 
 
735
  // oh hey, while we've got an active user let's check the header
 
736
  ASSERT_FALSE (g_settings_get_boolean (indicator_settings, show_name_key));
 
737
  ASSERT_FALSE (g_settings_get_boolean (mock_settings, error_key));
 
738
  check_header ("", "system-devices-panel", "System");
 
739
  g_settings_set_boolean (indicator_settings, show_name_key, true);
 
740
  wait_for_signal (action_group, "action-state-changed");
 
741
  check_header ("Third Doctor", "system-devices-panel", "System, Third Doctor");
 
742
  g_settings_set_boolean (mock_settings, error_key, true);
 
743
  wait_for_signal (action_group, "action-state-changed");
 
744
  check_header ("Third Doctor", "system-devices-panel-alert", "System, Third Doctor (Attention Required)");
 
745
  g_settings_reset (mock_settings, error_key);
 
746
  g_settings_reset (indicator_settings, show_name_key);
 
747
  wait_for_menu_resync ();
 
748
 
 
749
  // try setting the max user count to 2...
 
750
  // since troughton has the fewest logins, he should get culled
 
751
  g_object_set (service, "max-users", 2, NULL);
 
752
  guint max_users;
 
753
  g_object_get (service, "max-users", &max_users, NULL);
 
754
  ASSERT_EQ (2, max_users);
 
755
  wait_for_menu_resync ();
 
756
  ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-greeter", &switch_menu, &pos));
 
757
  ASSERT_EQ (0, pos);
 
758
  ASSERT_EQ (4, g_menu_model_get_n_items (switch_menu));
 
759
  check_label ("First Doctor", switch_menu, 2);
 
760
  check_label ("Third Doctor", switch_menu, 3);
 
761
  g_clear_object (&switch_menu);
 
762
 
 
763
  // add some more, test sorting and culling.
 
764
  // add in all the doctors, but only show 7, and make msmith the current session
 
765
  g_object_set (service, "max-users", 7, NULL);
 
766
  g_object_get (service, "max-users", &max_users, NULL);
 
767
  ASSERT_EQ (7, max_users);
 
768
  for (int i=3; i<12; ++i)
 
769
    {
 
770
      IndicatorSessionUser * u = g_new0 (IndicatorSessionUser, 1);
 
771
      u->is_current_user = false;
 
772
      u->is_logged_in = false;
 
773
      u->uid = 101 + i;
 
774
      u->login_frequency = account_info[i].login_frequency;
 
775
      u->user_name = g_strdup (account_info[i].user_name);
 
776
      u->real_name = g_strdup (account_info[i].real_name);
 
777
      indicator_session_users_mock_add_user (INDICATOR_SESSION_USERS_MOCK(mock_users), u);
 
778
      users[i] = u;
 
779
    }
 
780
  users[2]->is_current_user = false;
 
781
  indicator_session_users_changed (mock_users, users[2]->uid);
 
782
  users[10]->is_current_user = true;
 
783
  users[10]->is_logged_in = true;
 
784
  indicator_session_users_changed (mock_users, users[10]->uid);
 
785
  wait_for_menu_resync ();
 
786
  ASSERT_TRUE (find_menu_item_for_action ("indicator.switch-to-greeter", &switch_menu, &pos));
 
787
  ASSERT_EQ (0, pos);
 
788
  ASSERT_EQ (9, g_menu_model_get_n_items (switch_menu));
 
789
  check_label ("Eleventh Doctor", switch_menu, 2);
 
790
  check_label ("Fifth Doctor", switch_menu, 3);
 
791
  check_label ("First Doctor", switch_menu, 4);
 
792
  check_label ("Fourth Doctor", switch_menu, 5);
 
793
  check_label ("Second Doctor", switch_menu, 6);
 
794
  check_label ("Tenth Doctor", switch_menu, 7);
 
795
  check_label ("Third Doctor", switch_menu, 8);
 
796
  g_clear_object (&switch_menu);
 
797
 
 
798
  // now switch to one of the doctors
 
799
  g_action_group_activate_action (G_ACTION_GROUP(action_group),
 
800
                                  "switch-to-user",
 
801
                                  g_variant_new_string("tbaker"));
 
802
  wait_for_signal (mock_settings, "changed::last-command");
 
803
  check_last_command_is ("switch-to-user::tbaker");
145
804
}