~alan-griffiths/miral/debug

« back to all changes in this revision

Viewing changes to miral-qt/tests/modules/Application/application_test.cpp

  • Committer: Gerry Boland
  • Date: 2016-06-01 22:06:51 UTC
  • mto: This revision was merged to the branch mainline in revision 178.
  • Revision ID: gerry.boland@canonical.com-20160601220651-ge508tffql4e7u7c
Import QtMir code into miral-qt subdirectory. Disabled by default, use -DMIRAL_ENABLE_QT=1 to build.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2015-2016 Canonical, Ltd.
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify it under
 
5
 * the terms of the GNU Lesser General Public License version 3, as published by
 
6
 * the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful, but WITHOUT
 
9
 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
 
10
 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
11
 * Lesser General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU Lesser General Public License
 
14
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 */
 
16
 
 
17
#include <gmock/gmock.h>
 
18
#include <gtest/gtest.h>
 
19
 
 
20
#include "qtmir_test.h"
 
21
 
 
22
#include <fake_mirsurface.h>
 
23
#include <fake_application_info.h>
 
24
#include <fake_session.h>
 
25
#include <mock_application_info.h>
 
26
#include <mock_session.h>
 
27
 
 
28
#include <QScopedPointer>
 
29
#include <QSignalSpy>
 
30
 
 
31
using namespace qtmir;
 
32
 
 
33
class ApplicationTests : public ::testing::QtMirTest
 
34
{
 
35
public:
 
36
    ApplicationTests()
 
37
        : fakeTimeSource(new FakeTimeSource)
 
38
    {
 
39
    }
 
40
 
 
41
    inline void suspend(QScopedPointer<Application> &application)
 
42
    {
 
43
        suspend(application.data());
 
44
    }
 
45
 
 
46
    inline void suspend(Application *application)
 
47
    {
 
48
        application->setRequestedState(Application::RequestedSuspended);
 
49
        auto session = dynamic_cast<Session*>(application->session());
 
50
 
 
51
        ASSERT_EQ(Application::InternalState::SuspendingWaitSession, application->internalState());
 
52
        ASSERT_EQ(Session::Suspending, session->state());
 
53
 
 
54
        QSignalSpy suspendProcessRequestedSpy(application, &Application::suspendProcessRequested);
 
55
 
 
56
        passTimeUntilTimerTimesOut(session->suspendTimer());
 
57
 
 
58
        ASSERT_EQ(Session::Suspended, session->state());
 
59
        ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, application->internalState());
 
60
        ASSERT_EQ(1, suspendProcessRequestedSpy.count());
 
61
 
 
62
        application->setProcessState(Application::ProcessSuspended);
 
63
 
 
64
        ASSERT_EQ(Application::InternalState::Suspended, application->internalState());
 
65
    }
 
66
 
 
67
    inline Application *createApplicationWithFakes()
 
68
    {
 
69
        Application *application = new Application(
 
70
                QSharedPointer<MockSharedWakelock>(&sharedWakelock, [](MockSharedWakelock *){}),
 
71
                QSharedPointer<FakeApplicationInfo>::create());
 
72
 
 
73
        application->setStopTimer(new FakeTimer(fakeTimeSource));
 
74
 
 
75
        return application;
 
76
    }
 
77
 
 
78
    inline Session *createSessionWithFakes()
 
79
    {
 
80
        using namespace ::testing;
 
81
        const QString appId("test-app");
 
82
        const pid_t procId = 1234;
 
83
 
 
84
        auto mirSession = std::make_shared<NiceMock<mir::scene::MockSession>>(appId.toStdString(), procId);
 
85
        Session* session = new Session(mirSession, promptSessionManager);
 
86
 
 
87
        FakeTimer *fakeTimer(new FakeTimer(fakeTimeSource));
 
88
        session->setSuspendTimer(fakeTimer);
 
89
 
 
90
        return session;
 
91
    }
 
92
 
 
93
    inline void passTimeUntilTimerTimesOut(AbstractTimer *timer)
 
94
    {
 
95
        FakeTimer *fakeTimer = dynamic_cast<FakeTimer*>(timer);
 
96
        if (fakeTimer->isRunning()) {
 
97
            fakeTimeSource->m_msecsSinceReference = fakeTimer->nextTimeoutTime() + 1;
 
98
            fakeTimer->update();
 
99
        }
 
100
    }
 
101
 
 
102
    QSharedPointer<FakeTimeSource> fakeTimeSource;
 
103
};
 
104
 
 
105
TEST_F(ApplicationTests, acquiresWakelockWhenRunningAndReleasesWhenSuspended)
 
106
{
 
107
    using namespace ::testing;
 
108
 
 
109
    QScopedPointer<Application> application(createApplicationWithFakes());
 
110
 
 
111
    application->setProcessState(Application::ProcessRunning);
 
112
 
 
113
    FakeSession *session = new FakeSession;
 
114
 
 
115
    application->setSession(session);
 
116
 
 
117
    ASSERT_EQ(Application::InternalState::Starting, application->internalState());
 
118
 
 
119
    session->setState(SessionInterface::Running);
 
120
 
 
121
    EXPECT_TRUE(sharedWakelock.enabled());
 
122
 
 
123
    ASSERT_EQ(Application::InternalState::Running, application->internalState());
 
124
 
 
125
    application->setRequestedState(Application::RequestedSuspended);
 
126
 
 
127
    ASSERT_EQ(SessionInterface::Suspending, session->state());
 
128
    ASSERT_EQ(Application::InternalState::SuspendingWaitSession, application->internalState());
 
129
 
 
130
    session->setState(SessionInterface::Suspended);
 
131
 
 
132
    ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, application->internalState());
 
133
 
 
134
    application->setProcessState(Application::ProcessSuspended);
 
135
 
 
136
    ASSERT_EQ(Application::InternalState::Suspended, application->internalState());
 
137
 
 
138
    EXPECT_FALSE(sharedWakelock.enabled());
 
139
}
 
140
 
 
141
TEST_F(ApplicationTests, checkResumeAcquiresWakeLock)
 
142
{
 
143
    using namespace ::testing;
 
144
 
 
145
    QScopedPointer<Application> application(createApplicationWithFakes());
 
146
    FakeSession *session = new FakeSession;
 
147
 
 
148
    // Get it running and then suspend it
 
149
    application->setProcessState(Application::ProcessRunning);
 
150
    application->setSession(session);
 
151
    session->setState(SessionInterface::Running);
 
152
    application->setRequestedState(Application::RequestedSuspended);
 
153
    session->setState(SessionInterface::Suspended);
 
154
    application->setProcessState(Application::ProcessSuspended);
 
155
    ASSERT_EQ(Application::InternalState::Suspended, application->internalState());
 
156
 
 
157
    EXPECT_FALSE(sharedWakelock.enabled());
 
158
 
 
159
    application->setRequestedState(Application::RequestedRunning);
 
160
 
 
161
    ASSERT_EQ(Application::InternalState::Running, application->internalState());
 
162
 
 
163
    EXPECT_TRUE(sharedWakelock.enabled());
 
164
}
 
165
 
 
166
TEST_F(ApplicationTests, checkRespawnAcquiresWakeLock)
 
167
{
 
168
    using namespace ::testing;
 
169
 
 
170
    QScopedPointer<Application> application(createApplicationWithFakes());
 
171
    FakeSession *session = new FakeSession;
 
172
 
 
173
    // Get it running, suspend it, and finally stop it
 
174
    application->setProcessState(Application::ProcessRunning);
 
175
    application->setSession(session);
 
176
    session->setState(SessionInterface::Running);
 
177
    application->setRequestedState(Application::RequestedSuspended);
 
178
    session->setState(SessionInterface::Suspended);
 
179
    application->setProcessState(Application::ProcessSuspended);
 
180
    ASSERT_EQ(Application::InternalState::Suspended, application->internalState());
 
181
    session->setState(SessionInterface::Stopped);
 
182
    application->setProcessState(Application::ProcessFailed);
 
183
    ASSERT_EQ(Application::InternalState::StoppedResumable, application->internalState());
 
184
 
 
185
    EXPECT_FALSE(sharedWakelock.enabled());
 
186
 
 
187
    QSignalSpy spyStartProcess(application.data(), SIGNAL(startProcessRequested()));
 
188
    application->setRequestedState(Application::RequestedRunning);
 
189
    ASSERT_EQ(1, spyStartProcess.count());
 
190
    application->setProcessState(Application::ProcessRunning);
 
191
 
 
192
    ASSERT_EQ(Application::InternalState::Starting, application->internalState());
 
193
 
 
194
    EXPECT_TRUE(sharedWakelock.enabled());
 
195
}
 
196
 
 
197
TEST_F(ApplicationTests, checkDashDoesNotImpactWakeLock)
 
198
{
 
199
    using namespace ::testing;
 
200
 
 
201
    EXPECT_CALL(sharedWakelock, acquire(_)).Times(0);
 
202
    EXPECT_CALL(sharedWakelock, release(_)).Times(0);
 
203
 
 
204
    auto applicationInfo = QSharedPointer<FakeApplicationInfo>::create();
 
205
    applicationInfo->m_appId = QString("unity8-dash");
 
206
 
 
207
    QScopedPointer<Application> application(new Application(
 
208
                QSharedPointer<MockSharedWakelock>(&sharedWakelock, [](MockSharedWakelock *){}),
 
209
                applicationInfo));
 
210
 
 
211
    application->setProcessState(Application::ProcessRunning);
 
212
 
 
213
    FakeSession *session = new FakeSession;
 
214
 
 
215
    application->setSession(session);
 
216
 
 
217
    ASSERT_EQ(Application::InternalState::Starting, application->internalState());
 
218
 
 
219
    session->setState(SessionInterface::Running);
 
220
 
 
221
    ASSERT_EQ(Application::InternalState::Running, application->internalState());
 
222
 
 
223
    application->setRequestedState(Application::RequestedSuspended);
 
224
 
 
225
    ASSERT_EQ(SessionInterface::Suspending, session->state());
 
226
    ASSERT_EQ(Application::InternalState::SuspendingWaitSession, application->internalState());
 
227
 
 
228
    session->setState(SessionInterface::Suspended);
 
229
 
 
230
    ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, application->internalState());
 
231
 
 
232
    application->setProcessState(Application::ProcessSuspended);
 
233
 
 
234
    ASSERT_EQ(Application::InternalState::Suspended, application->internalState());
 
235
 
 
236
    application->setRequestedState(Application::RequestedRunning);
 
237
 
 
238
    ASSERT_EQ(Application::InternalState::Running, application->internalState());
 
239
}
 
240
 
 
241
TEST_F(ApplicationTests, emitsStoppedWhenRunningAppStops)
 
242
{
 
243
    using namespace ::testing;
 
244
 
 
245
    QScopedPointer<Application> application(createApplicationWithFakes());
 
246
 
 
247
    application->setProcessState(Application::ProcessRunning);
 
248
 
 
249
    FakeSession *session = new FakeSession;
 
250
    application->setSession(session);
 
251
 
 
252
    QSignalSpy spyAppStopped(application.data(), SIGNAL(stopped()));
 
253
 
 
254
    session->setState(SessionInterface::Running);
 
255
 
 
256
    ASSERT_EQ(Application::InternalState::Running, application->internalState());
 
257
 
 
258
    ////
 
259
    // Simulate a running application closing itself (ie, ending its own process)
 
260
 
 
261
    session->setState(SessionInterface::Stopped);
 
262
 
 
263
    ASSERT_EQ(Application::InternalState::Stopped, application->internalState());
 
264
 
 
265
    application->setProcessState(Application::ProcessStopped);
 
266
 
 
267
    ASSERT_EQ(1, spyAppStopped.count());
 
268
}
 
269
 
 
270
/**
 
271
 * Regression test for https://bugs.launchpad.net/qtmir/+bug/1485608
 
272
 * In that case, the camera-app closes itself right after unity8 unfocus it (and thus requests it to be suspended).
 
273
 */
 
274
TEST_F(ApplicationTests, emitsStoppedWhenAppStopsWhileSuspending)
 
275
{
 
276
    using namespace ::testing;
 
277
 
 
278
    QScopedPointer<Application> application(createApplicationWithFakes());
 
279
 
 
280
    application->setProcessState(Application::ProcessRunning);
 
281
 
 
282
    Session *session = createSessionWithFakes();
 
283
    application->setSession(session);
 
284
 
 
285
    QSignalSpy spyAppStopped(application.data(), SIGNAL(stopped()));
 
286
 
 
287
    FakeMirSurface *surface = new FakeMirSurface;
 
288
    session->registerSurface(surface);
 
289
    surface->drawFirstFrame();
 
290
 
 
291
    ASSERT_EQ(Application::InternalState::Running, application->internalState());
 
292
 
 
293
    application->setRequestedState(Application::RequestedSuspended);
 
294
 
 
295
    ASSERT_EQ(Application::InternalState::SuspendingWaitSession, application->internalState());
 
296
 
 
297
    // Now the application closes itself (ie, ending its own process)
 
298
    // Session always responds before the process state.
 
299
    session->setLive(false);
 
300
    application->setProcessState(Application::ProcessStopped);
 
301
 
 
302
    ASSERT_EQ(Application::InternalState::Stopped, application->internalState());
 
303
    ASSERT_EQ(1, spyAppStopped.count());
 
304
 
 
305
    // clean up
 
306
    delete surface;
 
307
}
 
308
 
 
309
TEST_F(ApplicationTests, doesNotEmitStoppedWhenKilledWhileSuspended)
 
310
{
 
311
    using namespace ::testing;
 
312
 
 
313
    QScopedPointer<Application> application(createApplicationWithFakes());
 
314
 
 
315
    application->setProcessState(Application::ProcessRunning);
 
316
 
 
317
    FakeSession *session = new FakeSession;
 
318
    application->setSession(session);
 
319
 
 
320
    QSignalSpy spyAppStopped(application.data(), SIGNAL(stopped()));
 
321
 
 
322
    session->setState(SessionInterface::Running);
 
323
 
 
324
    ASSERT_EQ(Application::InternalState::Running, application->internalState());
 
325
 
 
326
    application->setRequestedState(Application::RequestedSuspended);
 
327
 
 
328
    ASSERT_EQ(SessionInterface::Suspending, session->state());
 
329
    ASSERT_EQ(Application::InternalState::SuspendingWaitSession, application->internalState());
 
330
 
 
331
    session->setState(SessionInterface::Suspended);
 
332
 
 
333
    ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, application->internalState());
 
334
 
 
335
    application->setProcessState(Application::ProcessSuspended);
 
336
 
 
337
    ///
 
338
    // Now simulate the process getting killed. Mir session always ends before
 
339
    // we get notified about the process state
 
340
 
 
341
    session->setState(SessionInterface::Stopped);
 
342
 
 
343
    application->setProcessState(Application::ProcessFailed);
 
344
 
 
345
    ASSERT_EQ(Application::InternalState::StoppedResumable, application->internalState());
 
346
 
 
347
    ASSERT_EQ(0, spyAppStopped.count());
 
348
 
 
349
}
 
350
 
 
351
TEST_F(ApplicationTests, passesIsTouchAppThrough)
 
352
{
 
353
    using namespace ::testing;
 
354
 
 
355
    auto mockApplicationInfo = QSharedPointer<MockApplicationInfo>(new NiceMock<MockApplicationInfo>("foo-app"));
 
356
    QScopedPointer<Application> application(new Application(
 
357
            QSharedPointer<MockSharedWakelock>(&sharedWakelock, [](MockSharedWakelock *){}),
 
358
            mockApplicationInfo, QStringList(), nullptr));
 
359
 
 
360
    ON_CALL(*mockApplicationInfo, isTouchApp()).WillByDefault(Return(true));
 
361
    ASSERT_TRUE(application->isTouchApp());
 
362
 
 
363
    ON_CALL(*mockApplicationInfo, isTouchApp()).WillByDefault(Return(false));
 
364
    ASSERT_FALSE(application->isTouchApp());
 
365
}
 
366
 
 
367
/*
 
368
 * A suspended application resumes itself while any of its surfaces is being closed.
 
369
 */
 
370
TEST_F(ApplicationTests, suspendedApplicationResumesWhileSurfaceBeingClosed)
 
371
{
 
372
    using namespace ::testing;
 
373
 
 
374
    QScopedPointer<Application> application(createApplicationWithFakes());
 
375
 
 
376
    application->setProcessState(Application::ProcessRunning);
 
377
 
 
378
    Session *session = createSessionWithFakes();
 
379
 
 
380
    application->setSession(session);
 
381
 
 
382
    FakeMirSurface *surface = new FakeMirSurface;
 
383
    session->registerSurface(surface);
 
384
    surface->drawFirstFrame();
 
385
 
 
386
    ASSERT_EQ(Application::InternalState::Running, application->internalState());
 
387
 
 
388
    // Add a second surface to ensure the application doesn't kill itself after it loses
 
389
    // one surface.
 
390
    FakeMirSurface *secondSurface = new FakeMirSurface;
 
391
    session->registerSurface(secondSurface);
 
392
    secondSurface->drawFirstFrame();
 
393
 
 
394
    suspend(application.data());
 
395
 
 
396
    QSignalSpy resumeProcessRequestedSpy(application.data(), &Application::resumeProcessRequested);
 
397
 
 
398
    surface->close();
 
399
 
 
400
    ASSERT_EQ(Application::InternalState::Running, application->internalState());
 
401
    ASSERT_EQ(1, resumeProcessRequestedSpy.count());
 
402
    ASSERT_EQ(Session::Running, session->state());
 
403
 
 
404
    // And goes back to sleep after the closing surface is gone
 
405
 
 
406
    QSignalSpy suspendProcessRequestedSpy(application.data(), &Application::suspendProcessRequested);
 
407
 
 
408
    delete surface;
 
409
 
 
410
    ASSERT_EQ(Application::InternalState::SuspendingWaitSession, application->internalState());
 
411
    ASSERT_EQ(Session::Suspending, session->state());
 
412
 
 
413
    passTimeUntilTimerTimesOut(session->suspendTimer());
 
414
 
 
415
    ASSERT_EQ(Session::Suspended, session->state());
 
416
    ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, application->internalState());
 
417
    ASSERT_EQ(1, suspendProcessRequestedSpy.count());
 
418
 
 
419
    application->setProcessState(Application::ProcessSuspended);
 
420
 
 
421
    ASSERT_EQ(Application::InternalState::Suspended, application->internalState());
 
422
 
 
423
    // clean up
 
424
    delete secondSurface;
 
425
}
 
426
 
 
427
TEST_F(ApplicationTests, quitsAfterLastSurfaceIsClosed)
 
428
{
 
429
    using namespace ::testing;
 
430
 
 
431
    QScopedPointer<Application> application(createApplicationWithFakes());
 
432
 
 
433
    application->setProcessState(Application::ProcessRunning);
 
434
 
 
435
    Session *session = createSessionWithFakes();
 
436
 
 
437
    application->setSession(session);
 
438
 
 
439
    FakeMirSurface *surface = new FakeMirSurface;
 
440
    session->registerSurface(surface);
 
441
    surface->drawFirstFrame();
 
442
 
 
443
    ASSERT_EQ(Application::InternalState::Running, application->internalState());
 
444
    ASSERT_EQ(Session::Running, session->state());
 
445
 
 
446
    FakeMirSurface *secondSurface = new FakeMirSurface;
 
447
    session->registerSurface(secondSurface);
 
448
    secondSurface->drawFirstFrame();
 
449
 
 
450
    delete surface;
 
451
 
 
452
    passTimeUntilTimerTimesOut(application->stopTimer());
 
453
 
 
454
    // All fine as there's still one surface left
 
455
    ASSERT_EQ(Application::InternalState::Running, application->internalState());
 
456
    ASSERT_EQ(Session::Running, session->state());
 
457
 
 
458
    delete secondSurface;
 
459
 
 
460
    QSignalSpy stopProcessRequestedSpy(application.data(), &Application::stopProcessRequested);
 
461
 
 
462
    passTimeUntilTimerTimesOut(application->stopTimer());
 
463
 
 
464
    // Ok, now the application should go way
 
465
    ASSERT_EQ(1, stopProcessRequestedSpy.count());
 
466
}
 
467
 
 
468
/*
 
469
 * Test that an application that is suspended after its session is stopped is closed
 
470
 *
 
471
 * Regression test for bug LP#1536133
 
472
 * (https://bugs.launchpad.net/canonical-devices-system-image/+bug/1536133)
 
473
 */
 
474
TEST_F(ApplicationTests, sessionStopsWhileBeingSuspended)
 
475
{
 
476
    using namespace ::testing;
 
477
 
 
478
    int argc = 0;
 
479
    char* argv[0];
 
480
    QCoreApplication qtApp(argc, argv); // app for deleteLater event
 
481
 
 
482
    QScopedPointer<Application> application(createApplicationWithFakes());
 
483
 
 
484
    application->setProcessState(Application::ProcessRunning);
 
485
 
 
486
    QPointer<Session> session(createSessionWithFakes());
 
487
 
 
488
    application->setSession(session);
 
489
 
 
490
    FakeMirSurface *surface = new FakeMirSurface;
 
491
    session->registerSurface(surface);
 
492
    surface->drawFirstFrame();
 
493
    ASSERT_EQ(Application::InternalState::Running, application->internalState());
 
494
 
 
495
    application->setRequestedState(Application::RequestedSuspended);
 
496
 
 
497
    ASSERT_EQ(Application::InternalState::SuspendingWaitSession, application->internalState());
 
498
 
 
499
    passTimeUntilTimerTimesOut(session->suspendTimer());
 
500
 
 
501
    ASSERT_EQ(Application::InternalState::SuspendingWaitProcess, application->internalState());
 
502
    QSignalSpy stopProcessRequestedSpy(application.data(), &Application::stopProcessRequested);
 
503
 
 
504
    // surface dies, followed by session
 
505
    surface->setLive(false);
 
506
    delete surface;
 
507
    surface = nullptr;
 
508
    session->setLive(false);
 
509
 
 
510
    // Session should have called deleteLater() on itself, as it's zombie and doesn't hold any surface
 
511
    // But DeferredDelete is special: likes to be called out specifically or it won't come out
 
512
    qtApp.sendPostedEvents(session.data(), QEvent::DeferredDelete);
 
513
    qtApp.sendPostedEvents();
 
514
 
 
515
    EXPECT_EQ(true, session.isNull());
 
516
    EXPECT_EQ(1, stopProcessRequestedSpy.count());
 
517
    EXPECT_EQ(Application::InternalState::Stopped, application->internalState());
 
518
}
 
519
 
 
520
/*
 
521
 * Test that an application that fails while suspended will stop on close request
 
522
 */
 
523
TEST_F(ApplicationTests, closeWhenSuspendedProcessFailed)
 
524
{
 
525
    using namespace ::testing;
 
526
 
 
527
    QScopedPointer<Application> application(createApplicationWithFakes());
 
528
 
 
529
    application->setProcessState(Application::ProcessRunning);
 
530
 
 
531
    QPointer<Session> session(createSessionWithFakes());
 
532
    application->setSession(session);
 
533
 
 
534
    FakeMirSurface *surface = new FakeMirSurface;
 
535
    session->registerSurface(surface);
 
536
    surface->drawFirstFrame();
 
537
    ASSERT_EQ(Application::InternalState::Running, application->internalState());
 
538
 
 
539
    suspend(application.data());
 
540
 
 
541
    // Process failed
 
542
    surface->setLive(false);
 
543
    session->setLive(false);
 
544
    application->setProcessState(Application::ProcessFailed);
 
545
 
 
546
    ASSERT_EQ(Application::InternalState::StoppedResumable, application->internalState());
 
547
 
 
548
    application->close();
 
549
 
 
550
    ASSERT_EQ(Application::InternalState::Stopped, application->internalState());
 
551
 
 
552
    // clean up
 
553
    delete surface;
 
554
}
 
555
 
 
556
/*
 
557
 If an application gets stopped (ie, loses its surfaces, session and process) while it's in Suspended
 
558
 state, it goes into StoppedResumable state.
 
559
 */
 
560
TEST_F(ApplicationTests, stoppedWhileSuspendedTurnsIntoStoppeResumable)
 
561
{
 
562
    using namespace ::testing;
 
563
 
 
564
    QScopedPointer<Application> application(createApplicationWithFakes());
 
565
 
 
566
    application->setProcessState(Application::ProcessRunning);
 
567
 
 
568
    Session *session = createSessionWithFakes();
 
569
 
 
570
    application->setSession(session);
 
571
 
 
572
    FakeMirSurface *surface = new FakeMirSurface;
 
573
    session->registerSurface(surface);
 
574
    surface->drawFirstFrame();
 
575
 
 
576
    ASSERT_EQ(Application::InternalState::Running, application->internalState());
 
577
 
 
578
    suspend(application);
 
579
 
 
580
    // Process gets killed. Mir objects respond first
 
581
    surface->setLive(false);
 
582
    session->setLive(false);
 
583
    delete surface; surface = nullptr;
 
584
 
 
585
    EXPECT_EQ(Application::InternalState::StoppedResumable, application->internalState());
 
586
 
 
587
    // And later comes upstart telling us about it
 
588
    application->setProcessState(Application::ProcessFailed);
 
589
 
 
590
    EXPECT_EQ(Application::InternalState::StoppedResumable, application->internalState());
 
591
}
 
592
 
 
593
/*
 
594
   Regression test for bug "App respawns if manually closed while it's launching"
 
595
   https://bugs.launchpad.net/ubuntu/+source/qtmir/+bug/1575577
 
596
 */
 
597
TEST_F(ApplicationTests, dontRespawnIfClosedWhileStillStartingUp)
 
598
{
 
599
    using namespace ::testing;
 
600
 
 
601
    QScopedPointer<Application> application(createApplicationWithFakes());
 
602
 
 
603
    application->setProcessState(Application::ProcessRunning);
 
604
 
 
605
    FakeSession *session = new FakeSession;
 
606
 
 
607
    application->setSession(session);
 
608
 
 
609
    QSignalSpy spyStartProcess(application.data(), SIGNAL(startProcessRequested()));
 
610
 
 
611
    // Close the application before it even gets a surface (it's still in "starting" state)
 
612
    application->close();
 
613
 
 
614
    session->setState(SessionInterface::Stopped);
 
615
 
 
616
    EXPECT_EQ(Application::InternalState::Stopped, application->internalState());
 
617
    EXPECT_EQ(0, spyStartProcess.count());
 
618
}