~mterry/indicator-sound/snap-root

« back to all changes in this revision

Viewing changes to tests/integration/indicator-sound-test-base.cpp

  • Committer: CI Train Bot
  • Author(s): Xavi Garcia Mena
  • Date: 2016-01-05 15:08:02 UTC
  • mfrom: (513.1.2 restore-osd-notifications)
  • Revision ID: ci-train-bot@canonical.com-20160105150802-9n0tg5ipbbq2qbab
This branch just readds the OSD notifications code, that was reverted in trunk as the corresponding silo was also rolled back after landing.
Approved by: PS Jenkins bot, Xavi Garcia

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2015 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
 * Author: Xavi Garcia <xavi.garcia.mena@canonical.com>
 
17
 */
 
18
 
 
19
#include "indicator-sound-test-base.h"
 
20
 
 
21
#include "dbus_menus_interface.h"
 
22
#include "dbus_properties_interface.h"
 
23
#include "dbus_accounts_interface.h"
 
24
#include "dbus_accountssound_interface.h"
 
25
#include "dbus_notifications_interface.h"
 
26
#include "dbus-types.h"
 
27
 
 
28
#include <gio/gio.h>
 
29
#include <chrono>
 
30
#include <thread>
 
31
 
 
32
#include <QSignalSpy>
 
33
#include "utils/dbus-pulse-volume.h"
 
34
 
 
35
using namespace QtDBusTest;
 
36
using namespace QtDBusMock;
 
37
using namespace std;
 
38
using namespace testing;
 
39
namespace mh = unity::gmenuharness;
 
40
 
 
41
namespace
 
42
{
 
43
    const int MAX_TIME_WAITING_FOR_NOTIFICATIONS = 2000;
 
44
}
 
45
 
 
46
IndicatorSoundTestBase::IndicatorSoundTestBase() :
 
47
    dbusMock(dbusTestRunner)
 
48
{
 
49
}
 
50
 
 
51
IndicatorSoundTestBase::~IndicatorSoundTestBase()
 
52
{
 
53
}
 
54
 
 
55
void IndicatorSoundTestBase::SetUp()
 
56
{
 
57
    setenv("XDG_DATA_DIRS", XDG_DATA_DIRS, true);
 
58
    setenv("DBUS_SYSTEM_BUS_ADDRESS", dbusTestRunner.systemBus().toStdString().c_str(), true);
 
59
    setenv("DBUS_SESSION_BUS_ADDRESS", dbusTestRunner.sessionBus().toStdString().c_str(), true);
 
60
    dbusMock.registerNotificationDaemon();
 
61
 
 
62
    dbusTestRunner.startServices();
 
63
 
 
64
    auto& notifications = notificationsMockInterface();
 
65
    notifications.AddMethod("org.freedesktop.Notifications",
 
66
                            "GetCapabilities",
 
67
                            "",
 
68
                            "as",
 
69
                            "ret = ['actions', 'body', 'body-markup', 'icon-static', 'image/svg+xml', 'x-canonical-private-synchronous', 'x-canonical-append', 'x-canonical-private-icon-only', 'x-canonical-truncation', 'private-synchronous', 'append', 'private-icon-only', 'truncation']"
 
70
                         ).waitForFinished();
 
71
 
 
72
    int waitedTime = 0;
 
73
    while (!dbusTestRunner.sessionConnection().interface()->isServiceRegistered("org.freedesktop.Notifications") && waitedTime < MAX_TIME_WAITING_FOR_NOTIFICATIONS)
 
74
    {
 
75
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
 
76
        waitedTime += 10;
 
77
    }
 
78
}
 
79
 
 
80
void IndicatorSoundTestBase::TearDown()
 
81
{
 
82
    unsetenv("XDG_DATA_DIRS");
 
83
    unsetenv("PULSE_SERVER");
 
84
    unsetenv("DBUS_SYSTEM_BUS_ADDRESS");
 
85
}
 
86
 
 
87
void gvariant_deleter(GVariant* varptr)
 
88
{
 
89
    if (varptr != nullptr)
 
90
    {
 
91
        g_variant_unref(varptr);
 
92
    }
 
93
}
 
94
 
 
95
std::shared_ptr<GVariant> IndicatorSoundTestBase::volume_variant(double volume)
 
96
{
 
97
    GVariantBuilder builder;
 
98
 
 
99
    g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
 
100
    g_variant_builder_add(&builder,
 
101
                          "{sv}",
 
102
                          "title",
 
103
                          g_variant_new_string("_Sound"));
 
104
 
 
105
    g_variant_builder_add(&builder,
 
106
                          "{sv}",
 
107
                          "accessible-desc",
 
108
                          g_variant_new_string("_Sound"));
 
109
 
 
110
    auto icon = g_themed_icon_new("icon");
 
111
    g_variant_builder_add(&builder,
 
112
                          "{sv}",
 
113
                          "icon",
 
114
                          g_icon_serialize(icon));
 
115
 
 
116
    g_variant_builder_add(&builder,
 
117
                          "{sv}",
 
118
                          "visible",
 
119
                          g_variant_new_boolean(true));
 
120
    return shared_ptr<GVariant>(g_variant_builder_end(&builder), &gvariant_deleter);
 
121
}
 
122
 
 
123
bool IndicatorSoundTestBase::setStreamRestoreVolume(QString const &role, double volume)
 
124
{
 
125
    QProcess setVolume;
 
126
    setVolume.start(VOLUME_SET_BIN, QStringList()
 
127
                                        << role
 
128
                                        << QString("%1").arg(volume));
 
129
    if (!setVolume.waitForStarted())
 
130
        return false;
 
131
 
 
132
    if (!setVolume.waitForFinished())
 
133
        return false;
 
134
 
 
135
    return setVolume.exitCode() == 0;
 
136
}
 
137
 
 
138
bool IndicatorSoundTestBase::setSinkVolume(double volume)
 
139
{
 
140
    QString volume_percentage = QString("%1\%").arg(volume*100);
 
141
    QProcess setVolume;
 
142
    setVolume.start("pactl", QStringList()
 
143
                                        << "-s"
 
144
                                        << "127.0.0.1"
 
145
                                        << "set-sink-volume"
 
146
                                        << "0"
 
147
                                        << volume_percentage);
 
148
    if (!setVolume.waitForStarted())
 
149
        return false;
 
150
 
 
151
    if (!setVolume.waitForFinished())
 
152
        return false;
 
153
 
 
154
    return setVolume.exitCode() == 0;
 
155
}
 
156
 
 
157
bool IndicatorSoundTestBase::clearGSettingsPlayers()
 
158
{
 
159
    QProcess clearPlayers;
 
160
 
 
161
    clearPlayers.start("gsettings", QStringList()
 
162
                                        << "set"
 
163
                                        << "com.canonical.indicator.sound"
 
164
                                        << "interested-media-players"
 
165
                                        << "[]");
 
166
    if (!clearPlayers.waitForStarted())
 
167
        return false;
 
168
 
 
169
    if (!clearPlayers.waitForFinished())
 
170
        return false;
 
171
 
 
172
    return clearPlayers.exitCode() == 0;
 
173
}
 
174
 
 
175
bool IndicatorSoundTestBase::startTestMprisPlayer(QString const& playerName)
 
176
{
 
177
    testPlayer1.terminate();
 
178
    testPlayer1.start(MEDIA_PLAYER_MPRIS_BIN, QStringList()
 
179
                                        << playerName);
 
180
    if (!testPlayer1.waitForStarted())
 
181
        return false;
 
182
 
 
183
 
 
184
    return true;
 
185
}
 
186
 
 
187
bool IndicatorSoundTestBase::setTestMprisPlayerProperty(QString const &testPlayer, QString const &property, bool value)
 
188
{
 
189
    QProcess setProperty;
 
190
    QString strValue;
 
191
    strValue = value ? "true" : "false";
 
192
 
 
193
    setProperty.start(MEDIA_PLAYER_MPRIS_UPDATE_BIN, QStringList()
 
194
                                        << testPlayer
 
195
                                        << property
 
196
                                        << strValue);
 
197
    if (!setProperty.waitForStarted())
 
198
        return false;
 
199
 
 
200
    if (!setProperty.waitForFinished())
 
201
        return false;
 
202
 
 
203
    return setProperty.exitCode() == 0;
 
204
}
 
205
 
 
206
bool IndicatorSoundTestBase::startTestSound(QString const &role)
 
207
{
 
208
    testSoundProcess.terminate();
 
209
    testSoundProcess.start("paplay", QStringList()
 
210
                                << "-s"
 
211
                                << "127.0.0.1"
 
212
                                << TEST_SOUND
 
213
                                << QString("--property=media.role=%1").arg(role));
 
214
 
 
215
    if (!testSoundProcess.waitForStarted())
 
216
        return false;
 
217
 
 
218
    return true;
 
219
}
 
220
 
 
221
void IndicatorSoundTestBase::stopTestSound()
 
222
{
 
223
    testSoundProcess.terminate();
 
224
}
 
225
 
 
226
void IndicatorSoundTestBase::startPulseDesktop(DevicePortType speakerPort, DevicePortType headphonesPort)
 
227
{
 
228
    try
 
229
    {
 
230
        pulseaudio.reset(
 
231
                new QProcessDBusService(DBusTypes::DBUS_PULSE,
 
232
                                        QDBusConnection::SessionBus,
 
233
                                        "pulseaudio",
 
234
                                        QStringList() << "--start"
 
235
                                                      << "-vvvv"
 
236
                                                      << "--disable-shm=true"
 
237
                                                      << "--daemonize=false"
 
238
                                                      << "--use-pid-file=false"
 
239
                                                      << "--system=false"
 
240
                                                      << "--exit-idle-time=-1"
 
241
                                                      << "-n"
 
242
                                                      << QString("--load=module-null-sink sink_name=indicator_sound_test_speaker sink_properties=device.bus=%1").arg(getDevicePortString(speakerPort))
 
243
                                                      << QString("--load=module-null-sink sink_name=indicator_sound_test_headphones sink_properties=device.bus=%1").arg(getDevicePortString(headphonesPort))
 
244
                                                      << "--log-target=file:/tmp/pulse-daemon.log"
 
245
                                                      << "--load=module-dbus-protocol"
 
246
                                                      << "--load=module-native-protocol-tcp auth-ip-acl=127.0.0.1"
 
247
                ));
 
248
        pulseaudio->start(dbusTestRunner.sessionConnection());
 
249
    }
 
250
    catch (exception const& e)
 
251
    {
 
252
        cout << "pulseaudio(): " << e.what() << endl;
 
253
        throw;
 
254
    }
 
255
}
 
256
 
 
257
void IndicatorSoundTestBase::startPulsePhone(DevicePortType speakerPort, DevicePortType headphonesPort)
 
258
{
 
259
    try
 
260
    {
 
261
        pulseaudio.reset(
 
262
                new QProcessDBusService(DBusTypes::DBUS_PULSE,
 
263
                                        QDBusConnection::SessionBus,
 
264
                                        "pulseaudio",
 
265
                                        QStringList() << "--start"
 
266
                                                      << "-vvvv"
 
267
                                                      << "--disable-shm=true"
 
268
                                                      << "--daemonize=false"
 
269
                                                      << "--use-pid-file=false"
 
270
                                                      << "--system=false"
 
271
                                                      << "--exit-idle-time=-1"
 
272
                                                      << "-n"
 
273
                                                      << QString("--load=module-null-sink sink_name=indicator_sound_test_speaker sink_properties=device.bus=%1").arg(getDevicePortString(speakerPort))
 
274
                                                      << QString("--load=module-null-sink sink_name=indicator_sound_test_headphones sink_properties=device.bus=%1").arg(getDevicePortString(headphonesPort))
 
275
                                                      << "--log-target=file:/tmp/pulse-daemon.log"
 
276
                                                      << QString("--load=module-stream-restore restore_device=false restore_muted=false fallback_table=%1").arg(STREAM_RESTORE_TABLE)
 
277
                                                      << "--load=module-dbus-protocol"
 
278
                                                      << "--load=module-native-protocol-tcp auth-ip-acl=127.0.0.1"
 
279
                ));
 
280
        pulseaudio->start(dbusTestRunner.sessionConnection());
 
281
    }
 
282
    catch (exception const& e)
 
283
    {
 
284
        cout << "pulseaudio(): " << e.what() << endl;
 
285
        throw;
 
286
    }
 
287
}
 
288
 
 
289
void IndicatorSoundTestBase::startAccountsService()
 
290
{
 
291
    try
 
292
    {
 
293
        accountsService.reset(
 
294
                new QProcessDBusService(DBusTypes::ACCOUNTS_SERVICE,
 
295
                                        QDBusConnection::SystemBus,
 
296
                                        ACCOUNTS_SERVICE_BIN,
 
297
                                        QStringList()));
 
298
        accountsService->start(dbusTestRunner.systemConnection());
 
299
 
 
300
        initializeAccountsInterface();
 
301
    }
 
302
    catch (exception const& e)
 
303
    {
 
304
        cout << "accountsService(): " << e.what() << endl;
 
305
        throw;
 
306
    }
 
307
}
 
308
 
 
309
void IndicatorSoundTestBase::startIndicator()
 
310
{
 
311
    try
 
312
    {
 
313
        setenv("PULSE_SERVER", "127.0.0.1", true);
 
314
        indicator.reset(
 
315
                new QProcessDBusService(DBusTypes::DBUS_NAME,
 
316
                                        QDBusConnection::SessionBus,
 
317
                                        SOUND_SERVICE_BIN,
 
318
                                        QStringList()));
 
319
        indicator->start(dbusTestRunner.sessionConnection());
 
320
    }
 
321
    catch (exception const& e)
 
322
    {
 
323
        cout << "startIndicator(): " << e.what() << endl;
 
324
        throw;
 
325
    }
 
326
}
 
327
 
 
328
mh::MenuMatcher::Parameters IndicatorSoundTestBase::desktopParameters()
 
329
{
 
330
    return mh::MenuMatcher::Parameters(
 
331
            "com.canonical.indicator.sound",
 
332
            { { "indicator", "/com/canonical/indicator/sound" } },
 
333
            "/com/canonical/indicator/sound/desktop");
 
334
}
 
335
 
 
336
mh::MenuMatcher::Parameters IndicatorSoundTestBase::phoneParameters()
 
337
{
 
338
    return mh::MenuMatcher::Parameters(
 
339
            "com.canonical.indicator.sound",
 
340
            { { "indicator", "/com/canonical/indicator/sound" } },
 
341
            "/com/canonical/indicator/sound/phone");
 
342
}
 
343
 
 
344
unity::gmenuharness::MenuItemMatcher IndicatorSoundTestBase::volumeSlider(double volume, QString const &label)
 
345
{
 
346
    return mh::MenuItemMatcher().radio()
 
347
            .label(label.toStdString())
 
348
            .round_doubles(0.1)
 
349
            .int32_attribute("target", 0)
 
350
            .double_attribute("min-value", 0.0)
 
351
            .double_attribute("max-value", 1.0)
 
352
            .double_attribute("step", 0.01)
 
353
            .string_attribute("x-canonical-type", "com.canonical.unity.slider")
 
354
            .themed_icon("max-icon", {"audio-volume-high-panel", "audio-volume-high", "audio-volume", "audio"})
 
355
            .themed_icon("min-icon", {"audio-volume-low-zero-panel", "audio-volume-low-zero", "audio-volume-low", "audio-volume", "audio"})
 
356
            .pass_through_double_attribute("action", volume);
 
357
}
 
358
 
 
359
unity::gmenuharness::MenuItemMatcher IndicatorSoundTestBase::silentModeSwitch(bool toggled)
 
360
{
 
361
    return mh::MenuItemMatcher::checkbox()
 
362
        .label("Silent Mode")
 
363
        .action("indicator.silent-mode")
 
364
        .toggled(toggled);
 
365
}
 
366
 
 
367
bool IndicatorSoundTestBase::waitMenuChange()
 
368
{
 
369
    if (signal_spy_menu_changed_)
 
370
    {
 
371
        return signal_spy_menu_changed_->wait();
 
372
    }
 
373
    return false;
 
374
}
 
375
 
 
376
bool IndicatorSoundTestBase::initializeMenuChangedSignal()
 
377
{
 
378
    if (!menu_interface_)
 
379
    {
 
380
        menu_interface_.reset(new MenusInterface("com.canonical.indicator.sound",
 
381
                                                 "/com/canonical/indicator/sound",
 
382
                                                 dbusTestRunner.sessionConnection(), 0));
 
383
    }
 
384
    if (menu_interface_)
 
385
    {
 
386
        qDebug() << "Waiting for signal";
 
387
        signal_spy_menu_changed_.reset(new QSignalSpy(menu_interface_.get(), &MenusInterface::Changed));
 
388
    }
 
389
    if (!menu_interface_ || !signal_spy_menu_changed_)
 
390
    {
 
391
        return false;
 
392
    }
 
393
    return true;
 
394
}
 
395
 
 
396
bool IndicatorSoundTestBase::waitVolumeChangedInIndicator()
 
397
{
 
398
    if (signal_spy_volume_changed_)
 
399
    {
 
400
        return signal_spy_volume_changed_->wait();
 
401
    }
 
402
    return false;
 
403
}
 
404
 
 
405
void IndicatorSoundTestBase::initializeAccountsInterface()
 
406
{
 
407
    auto username = qgetenv("USER");
 
408
    if (username != "")
 
409
    {
 
410
        main_accounts_interface_.reset(new AccountsInterface("org.freedesktop.Accounts",
 
411
                                                        "/org/freedesktop/Accounts",
 
412
                                                        dbusTestRunner.systemConnection(), 0));
 
413
 
 
414
        QDBusReply<QDBusObjectPath> userResp = main_accounts_interface_->call(QLatin1String("FindUserByName"),
 
415
                                                                  QLatin1String(username));
 
416
 
 
417
        if (!userResp.isValid())
 
418
        {
 
419
            qWarning() << "SetVolume::initializeAccountsInterface(): D-Bus error: " << userResp.error().message();
 
420
        }
 
421
 
 
422
        auto userPath = userResp.value().path();
 
423
        if (userPath != "")
 
424
        {
 
425
            std::unique_ptr<AccountsSoundInterface> soundInterface(new AccountsSoundInterface("org.freedesktop.Accounts",
 
426
                                                                    userPath,
 
427
                                                                    dbusTestRunner.systemConnection(), 0));
 
428
 
 
429
            accounts_interface_.reset(new DBusPropertiesInterface("org.freedesktop.Accounts",
 
430
                                                                userPath,
 
431
                                                                dbusTestRunner.systemConnection(), 0));
 
432
            if (!accounts_interface_->isValid())
 
433
            {
 
434
                qWarning() << "SetVolume::initializeAccountsInterface(): D-Bus error: " << accounts_interface_->lastError().message();
 
435
            }
 
436
            signal_spy_volume_changed_.reset(new QSignalSpy(accounts_interface_.get(),&DBusPropertiesInterface::PropertiesChanged));
 
437
        }
 
438
    }
 
439
}
 
440
 
 
441
OrgFreedesktopDBusMockInterface& IndicatorSoundTestBase::notificationsMockInterface()
 
442
{
 
443
    return dbusMock.mockInterface("org.freedesktop.Notifications",
 
444
                                   "/org/freedesktop/Notifications",
 
445
                                   "org.freedesktop.Notifications",
 
446
                                   QDBusConnection::SessionBus);
 
447
}
 
448
 
 
449
bool IndicatorSoundTestBase::setActionValue(const QString & action, QVariant value)
 
450
{
 
451
    QDBusInterface actionsInterface(DBusTypes::DBUS_NAME,
 
452
                                    DBusTypes::MAIN_SERVICE_PATH,
 
453
                                    DBusTypes::ACTIONS_INTERFACE,
 
454
                                    dbusTestRunner.sessionConnection());
 
455
 
 
456
    QDBusVariant dbusVar(value);
 
457
    auto resp = actionsInterface.call("SetState",
 
458
                                      action,
 
459
                                      QVariant::fromValue(dbusVar),
 
460
                                      QVariant::fromValue(QVariantMap()));
 
461
 
 
462
    if (resp.type() == QDBusMessage::ErrorMessage)
 
463
    {
 
464
        qCritical() << "IndicatorSoundTestBase::setActionValue(): Failed to set value for action "
 
465
                    << action
 
466
                    << " "
 
467
                    << resp.errorMessage();
 
468
        return false;
 
469
    }
 
470
    else
 
471
    {
 
472
        return true;
 
473
    }
 
474
}
 
475
 
 
476
bool IndicatorSoundTestBase::pressNotificationButton(int id, const QString & button)
 
477
{
 
478
    OrgFreedesktopDBusMockInterface actionsInterface("org.freedesktop.Notifications",
 
479
                                                     "/org/freedesktop/Notifications",
 
480
                                                     dbusTestRunner.sessionConnection());
 
481
 
 
482
    actionsInterface.EmitSignal(
 
483
            "org.freedesktop.Notifications",
 
484
                            "ActionInvoked", "us", QVariantList() << id << button);
 
485
 
 
486
    return true;
 
487
}
 
488
 
 
489
bool IndicatorSoundTestBase::qDBusArgumentToMap(QVariant const& variant, QVariantMap& map)
 
490
{
 
491
    if (variant.canConvert<QDBusArgument>())
 
492
    {
 
493
        QDBusArgument value(variant.value<QDBusArgument>());
 
494
        if (value.currentType() == QDBusArgument::MapType)
 
495
        {
 
496
            value >> map;
 
497
            return true;
 
498
        }
 
499
    }
 
500
    return false;
 
501
}
 
502
 
 
503
void IndicatorSoundTestBase::checkVolumeNotification(double volume, QString const& label, bool isLoud, QVariantList call)
 
504
{
 
505
    QString icon;
 
506
    if (volume <= 0.0)
 
507
    {
 
508
        icon = "audio-volume-muted";
 
509
    }
 
510
    else if (volume <= 0.3)
 
511
    {
 
512
        icon = "audio-volume-low";
 
513
    }
 
514
    else if (volume <= 0.7)
 
515
    {
 
516
        icon = "audio-volume-medium";
 
517
    }
 
518
    else
 
519
    {
 
520
        icon = "audio-volume-high";
 
521
    }
 
522
 
 
523
    ASSERT_NE(call.size(), 0);
 
524
    EXPECT_EQ("Notify", call.at(0));
 
525
 
 
526
    QVariantList const& args(call.at(1).toList());
 
527
    ASSERT_EQ(8, args.size());
 
528
    EXPECT_EQ("indicator-sound", args.at(0));
 
529
    EXPECT_EQ(icon, args.at(2));
 
530
    EXPECT_EQ("Volume", args.at(3));
 
531
    EXPECT_EQ(label, args.at(4));
 
532
    EXPECT_EQ(QStringList(), args.at(5));
 
533
 
 
534
    QVariantMap hints;
 
535
    ASSERT_TRUE(qDBusArgumentToMap(args.at(6), hints));
 
536
    ASSERT_TRUE(hints.contains("value"));
 
537
    ASSERT_TRUE(hints.contains("x-canonical-non-shaped-icon"));
 
538
    ASSERT_TRUE(hints.contains("x-canonical-value-bar-tint"));
 
539
    ASSERT_TRUE(hints.contains("x-canonical-private-synchronous"));
 
540
 
 
541
    EXPECT_EQ(volume*100, hints["value"]);
 
542
    EXPECT_EQ(true, hints["x-canonical-non-shaped-icon"]);
 
543
    EXPECT_EQ(isLoud, hints["x-canonical-value-bar-tint"]);
 
544
    EXPECT_EQ(true, hints["x-canonical-private-synchronous"]);
 
545
}
 
546
 
 
547
void IndicatorSoundTestBase::checkHighVolumeNotification(QVariantList call)
 
548
{
 
549
    ASSERT_NE(call.size(), 0);
 
550
    EXPECT_EQ("Notify", call.at(0));
 
551
 
 
552
    QVariantList const& args(call.at(1).toList());
 
553
    ASSERT_EQ(8, args.size());
 
554
    EXPECT_EQ("indicator-sound", args.at(0));
 
555
    EXPECT_EQ("Volume", args.at(3));
 
556
}
 
557
 
 
558
void IndicatorSoundTestBase::checkCloseNotification(int id, QVariantList call)
 
559
{
 
560
    EXPECT_EQ("CloseNotification", call.at(0));
 
561
    QVariantList const& args(call.at(1).toList());
 
562
    ASSERT_EQ(1, args.size());
 
563
}
 
564
 
 
565
void IndicatorSoundTestBase::checkNotificationWithNoArgs(QString const& method, QVariantList call)
 
566
{
 
567
    EXPECT_EQ(method, call.at(0));
 
568
    QVariantList const& args(call.at(1).toList());
 
569
    ASSERT_EQ(0, args.size());
 
570
}
 
571
 
 
572
int IndicatorSoundTestBase::getNotificationID(QVariantList call)
 
573
{
 
574
    if (call.size() == 0)
 
575
    {
 
576
        return -1;
 
577
    }
 
578
    QVariantList const& args(call.at(1).toList());
 
579
    if (args.size() != 8)
 
580
    {
 
581
        return -1;
 
582
    }
 
583
    if (args.at(0) != "indicator-sound")
 
584
    {
 
585
        return -1;
 
586
    }
 
587
 
 
588
    bool isInt;
 
589
    int id = args.at(1).toInt(&isInt);
 
590
    if (!isInt)
 
591
    {
 
592
        return -1;
 
593
    }
 
594
    return id;
 
595
}
 
596
 
 
597
bool IndicatorSoundTestBase::activateHeadphones(bool headphonesActive)
 
598
{
 
599
    QProcess pacltProcess;
 
600
 
 
601
    QString defaultSinkName = "indicator_sound_test_speaker";
 
602
    QString suspendedSinkName = "indicator_sound_test_headphones";
 
603
    if (headphonesActive)
 
604
    {
 
605
        defaultSinkName = "indicator_sound_test_headphones";
 
606
        suspendedSinkName = "indicator_sound_test_speaker";
 
607
    }
 
608
 
 
609
    pacltProcess.start("pactl", QStringList() << "-s"
 
610
                                              << "127.0.0.1"
 
611
                                              << "set-default-sink"
 
612
                                              << defaultSinkName);
 
613
    if (!pacltProcess.waitForStarted())
 
614
        return false;
 
615
 
 
616
    if (!pacltProcess.waitForFinished())
 
617
        return false;
 
618
 
 
619
    pacltProcess.start("pactl", QStringList() << "-s"
 
620
                                              << "127.0.0.1"
 
621
                                              << "suspend-sink"
 
622
                                              << defaultSinkName
 
623
                                              << "0");
 
624
    if (!pacltProcess.waitForStarted())
 
625
        return false;
 
626
 
 
627
    if (!pacltProcess.waitForFinished())
 
628
        return false;
 
629
 
 
630
    pacltProcess.start("pactl", QStringList() << "-s"
 
631
                                              << "127.0.0.1"
 
632
                                              << "suspend-sink"
 
633
                                              << suspendedSinkName
 
634
                                              << "1");
 
635
    if (!pacltProcess.waitForStarted())
 
636
        return false;
 
637
 
 
638
    if (!pacltProcess.waitForFinished())
 
639
        return false;
 
640
 
 
641
    return pacltProcess.exitCode() == 0;
 
642
}
 
643
 
 
644
QString IndicatorSoundTestBase::getDevicePortString(DevicePortType port)
 
645
{
 
646
    QString portString;
 
647
 
 
648
    switch (port)
 
649
    {
 
650
    case WIRED:
 
651
        portString = "wired";
 
652
        break;
 
653
    case BLUETOOTH:
 
654
        portString = "bluetooth";
 
655
        break;
 
656
    case USB:
 
657
        portString = "usb";
 
658
        break;
 
659
    case HDMI:
 
660
        portString = "hdmi";
 
661
        break;
 
662
    default:
 
663
        portString = "not_defined";
 
664
        break;
 
665
    }
 
666
 
 
667
    return portString;
 
668
}
 
669
 
 
670
void IndicatorSoundTestBase::checkPortDevicesLabels(DevicePortType speakerPort, DevicePortType headphonesPort)
 
671
{
 
672
    double INITIAL_VOLUME = 0.0;
 
673
 
 
674
    QString speakerString;
 
675
    QString speakerStringMenu;
 
676
    switch(speakerPort)
 
677
    {
 
678
    case WIRED:
 
679
        speakerString = "Speakers";
 
680
        speakerStringMenu = "Volume";
 
681
        break;
 
682
    case BLUETOOTH:
 
683
        speakerString = "Bluetooth speaker";
 
684
        speakerStringMenu = "Volume (Bluetooth)";
 
685
        break;
 
686
    case USB:
 
687
        speakerString = "Usb speaker";
 
688
        speakerStringMenu = "Volume (Usb)";
 
689
        break;
 
690
    case HDMI:
 
691
        speakerString = "HDMI speaker";
 
692
        speakerStringMenu = "Volume (HDMI)";
 
693
        break;
 
694
    }
 
695
 
 
696
    QString headphonesString;
 
697
    QString headphonesStringMenu;
 
698
    switch(headphonesPort)
 
699
    {
 
700
    case WIRED:
 
701
        headphonesString = "Headphones";
 
702
        headphonesStringMenu = "Volume (Headphones)";
 
703
        break;
 
704
    case BLUETOOTH:
 
705
        headphonesString = "Bluetooth headphones";
 
706
        headphonesStringMenu = "Volume (Bluetooth headphones)";
 
707
        break;
 
708
    case USB:
 
709
        headphonesString = "Usb headphones";
 
710
        headphonesStringMenu = "Volume (Usb headphones)";
 
711
        break;
 
712
    case HDMI:
 
713
        headphonesString = "HDMI headphones";
 
714
        headphonesStringMenu = "Volume (HDMI headphones)";
 
715
        break;
 
716
    }
 
717
 
 
718
    QSignalSpy notificationsSpy(&notificationsMockInterface(),
 
719
                                   SIGNAL(MethodCalled(const QString &, const QVariantList &)));
 
720
 
 
721
    ASSERT_NO_THROW(startAccountsService());
 
722
    ASSERT_NO_THROW(startPulsePhone(speakerPort, headphonesPort));
 
723
 
 
724
    // initialize volumes in pulseaudio
 
725
    EXPECT_TRUE(setStreamRestoreVolume("alert", INITIAL_VOLUME));
 
726
    EXPECT_TRUE(setStreamRestoreVolume("multimedia", INITIAL_VOLUME));
 
727
 
 
728
    // start now the indicator, so it picks the new volumes
 
729
    ASSERT_NO_THROW(startIndicator());
 
730
 
 
731
    // if the speaker is the normal one it does not emit any notification, as that's
 
732
    // the default one.
 
733
    // for the rest it notifies the output
 
734
    if (speakerPort != WIRED)
 
735
    {
 
736
        WAIT_FOR_SIGNALS(notificationsSpy, 3);
 
737
 
 
738
        // the first time we also have the calls to
 
739
        // GetServerInformation and GetCapabilities
 
740
        checkNotificationWithNoArgs("GetServerInformation", notificationsSpy.at(0));
 
741
        checkNotificationWithNoArgs("GetCapabilities", notificationsSpy.at(1));
 
742
        checkVolumeNotification(INITIAL_VOLUME, speakerString, false, notificationsSpy.at(2));
 
743
        notificationsSpy.clear();
 
744
    }
 
745
 
 
746
    notificationsSpy.clear();
 
747
    // activate the headphones
 
748
    EXPECT_TRUE(activateHeadphones(true));
 
749
 
 
750
    if (speakerPort == WIRED)
 
751
    {
 
752
        WAIT_FOR_SIGNALS(notificationsSpy, 3);
 
753
 
 
754
        // the first time we also have the calls to
 
755
        // GetServerInformation and GetCapabilities
 
756
        checkNotificationWithNoArgs("GetServerInformation", notificationsSpy.at(0));
 
757
        checkNotificationWithNoArgs("GetCapabilities", notificationsSpy.at(1));
 
758
        checkVolumeNotification(INITIAL_VOLUME, headphonesString, false, notificationsSpy.at(2));
 
759
        notificationsSpy.clear();
 
760
    }
 
761
    else
 
762
    {
 
763
        WAIT_FOR_SIGNALS(notificationsSpy, 2);
 
764
        checkNotificationWithNoArgs("GetCapabilities", notificationsSpy.at(0));
 
765
        checkVolumeNotification(INITIAL_VOLUME, headphonesString, false, notificationsSpy.at(1));
 
766
        notificationsSpy.clear();
 
767
    }
 
768
 
 
769
    // check the label in the menu
 
770
    EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters())
 
771
        .item(mh::MenuItemMatcher()
 
772
            .action("indicator.root")
 
773
            .string_attribute("x-canonical-type", "com.canonical.indicator.root")
 
774
            .string_attribute("x-canonical-scroll-action", "indicator.scroll")
 
775
            .string_attribute("x-canonical-secondary-action", "indicator.mute")
 
776
            .string_attribute("submenu-action", "indicator.indicator-shown")
 
777
            .mode(mh::MenuItemMatcher::Mode::starts_with)
 
778
            .submenu()
 
779
            .item(mh::MenuItemMatcher()
 
780
                .section()
 
781
                .item(silentModeSwitch(false))
 
782
                .item(volumeSlider(INITIAL_VOLUME, headphonesStringMenu))
 
783
            )
 
784
        ).match());
 
785
 
 
786
    // deactivate the headphones
 
787
    EXPECT_TRUE(activateHeadphones(false));
 
788
 
 
789
    WAIT_FOR_SIGNALS(notificationsSpy, 2);
 
790
    checkNotificationWithNoArgs("GetCapabilities", notificationsSpy.at(0));
 
791
    checkVolumeNotification(INITIAL_VOLUME, speakerString, false, notificationsSpy.at(1));
 
792
    notificationsSpy.clear();
 
793
 
 
794
    // check the label in the menu
 
795
    EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters())
 
796
        .item(mh::MenuItemMatcher()
 
797
            .action("indicator.root")
 
798
            .string_attribute("x-canonical-type", "com.canonical.indicator.root")
 
799
            .string_attribute("x-canonical-scroll-action", "indicator.scroll")
 
800
            .string_attribute("x-canonical-secondary-action", "indicator.mute")
 
801
            .string_attribute("submenu-action", "indicator.indicator-shown")
 
802
            .mode(mh::MenuItemMatcher::Mode::starts_with)
 
803
            .submenu()
 
804
            .item(mh::MenuItemMatcher()
 
805
                .section()
 
806
                .item(silentModeSwitch(false))
 
807
                .item(volumeSlider(INITIAL_VOLUME, speakerStringMenu))
 
808
            )
 
809
        ).match());
 
810
}
 
811
 
 
812
bool IndicatorSoundTestBase::setVolumeUntilAccountsIsConnected(double volume)
 
813
{
 
814
    int RETRY_TIME = 5000;
 
815
 
 
816
    setActionValue("volume", QVariant::fromValue(volume));
 
817
    while(!signal_spy_volume_changed_->wait(10) && RETRY_TIME)
 
818
    {
 
819
        RETRY_TIME -= 10;
 
820
        setActionValue("volume", QVariant::fromValue(volume));
 
821
    }
 
822
    return (signal_spy_volume_changed_->count() != 0);
 
823
}