summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorDaniel d'Andrada <daniel.dandrada@canonical.com>2015-04-10 11:54:44 -0300
committerDaniel d'Andrada <daniel.dandrada@canonical.com>2015-04-10 11:54:44 -0300
commit0774ce8ea08d3298a98af7660104d7ea05589ec7 (patch)
treeb1987ad83b0b21ec6b4795ac05b3d1614a2a3b63 /tests
parentf7fdcfffd0e41f124c296801214b779dae33acb6 (diff)
parentb9e9716a8d7e3cc8e38e58d94622eed5a68cc302 (diff)
Merge trunk
Diffstat (limited to 'tests')
-rw-r--r--tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h3
-rw-r--r--tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp35
-rw-r--r--tests/mirserver/Screen/screen_test.cpp5
-rw-r--r--tests/modules/Application/application_test.cpp14
-rw-r--r--tests/modules/ApplicationManager/application_manager_test.cpp80
-rw-r--r--tests/modules/MirSurfaceItem/mirsurfaceitem_test.cpp58
-rw-r--r--tests/modules/SharedWakelock/CMakeLists.txt6
-rw-r--r--tests/modules/SharedWakelock/sharedwakelock_test.cpp405
-rw-r--r--tests/modules/common/mock_shared_wakelock.h41
9 files changed, 486 insertions, 161 deletions
diff --git a/tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h b/tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h
index eece027..ec4a80d 100644
--- a/tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h
+++ b/tests/mirserver/QtEventFeeder/mock_qtwindowsystem.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 Canonical, Ltd.
+ * Copyright (C) 2014-2015 Canonical, Ltd.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License version 3, as published by
@@ -34,6 +34,7 @@ public:
MOCK_METHOD4(handleTouchEvent, void(ulong timestamp, QTouchDevice *device,
const QList<struct QWindowSystemInterface::TouchPoint> &points,
Qt::KeyboardModifiers mods));
+ MOCK_METHOD4(handleMouseEvent, void(ulong, QPointF, Qt::MouseButton, Qt::KeyboardModifiers));
};
namespace testing
diff --git a/tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp b/tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp
index 0514827..30c4d10 100644
--- a/tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp
+++ b/tests/mirserver/QtEventFeeder/qteventfeeder_test.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 Canonical, Ltd.
+ * Copyright (C) 2014-2015 Canonical, Ltd.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License version 3, as published by
@@ -15,6 +15,8 @@
*
*/
+#define MIR_INCLUDE_DEPRECATED_EVENT_HEADER
+
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -191,34 +193,3 @@ TEST_F(QtEventFeederTest, PressSameTouchTwice)
ASSERT_TRUE(Mock::VerifyAndClearExpectations(mockWindowSystem));
}
-TEST_F(QtEventFeederTest, IgnoreHovering)
-{
- setIrrelevantMockWindowSystemExpectations();
- EXPECT_CALL(*mockWindowSystem, handleTouchEvent(_,_,_,_)).Times(0);
-
- MirEvent mirEvent;
- mirEvent.type = mir_event_type_motion;
- mirEvent.motion.pointer_count = 1;
- mirEvent.motion.pointer_coordinates[0].id = 0;
- mirEvent.motion.pointer_coordinates[0].x = 10;
- mirEvent.motion.pointer_coordinates[0].y = 10;
- mirEvent.motion.pointer_coordinates[0].touch_major = 1;
- mirEvent.motion.pointer_coordinates[0].touch_minor = 1;
- mirEvent.motion.pointer_coordinates[0].pressure = 10;
- mirEvent.motion.action = mir_motion_action_hover_enter;
- mirEvent.motion.event_time = 123 * 1000000;
-
- qtEventFeeder->dispatch(mirEvent);
-
- mirEvent.motion.pointer_coordinates[0].x = 20;
- mirEvent.motion.pointer_coordinates[0].y = 20;
- mirEvent.motion.action = mir_motion_action_hover_move;
- mirEvent.motion.event_time = 125 * 1000000;
-
- qtEventFeeder->dispatch(mirEvent);
-
- mirEvent.motion.action = mir_motion_action_hover_exit;
- mirEvent.motion.event_time = 127 * 1000000;
-
- qtEventFeeder->dispatch(mirEvent);
-}
diff --git a/tests/mirserver/Screen/screen_test.cpp b/tests/mirserver/Screen/screen_test.cpp
index 3fe4c9e..be0461d 100644
--- a/tests/mirserver/Screen/screen_test.cpp
+++ b/tests/mirserver/Screen/screen_test.cpp
@@ -51,6 +51,11 @@ mg::DisplayConfigurationOutput const fake_output
TEST(ScreenTest, OrientationSensor)
{
+ if (!qEnvironmentVariableIsSet("QT_ACCEL_FILEPATH")) {
+ // Trick Qt >= 5.4.1 to load the generic sensors
+ qputenv("QT_ACCEL_FILEPATH", "dummy");
+ }
+
Screen::skipDBusRegistration = true;
Screen *screen = new Screen(fake_output);
diff --git a/tests/modules/Application/application_test.cpp b/tests/modules/Application/application_test.cpp
index 488a598..b201917 100644
--- a/tests/modules/Application/application_test.cpp
+++ b/tests/modules/Application/application_test.cpp
@@ -34,7 +34,7 @@ TEST_F(ApplicationTests, checkFocusAcquiresWakeLock)
{
using namespace ::testing;
- EXPECT_CALL(sharedWakelock, createWakelock()).Times(1);
+ EXPECT_CALL(sharedWakelock, acquire(_)).Times(1);
startApplication(123, "app");
applicationManager.focusApplication("app");
@@ -50,14 +50,14 @@ TEST_F(ApplicationTests, checkSuspendReleasesWakeLock)
applicationManager.focusApplication("app");
Q_EMIT session->suspended();
- EXPECT_FALSE(sharedWakelock.wakelockHeld());
+ EXPECT_FALSE(sharedWakelock.enabled());
}
TEST_F(ApplicationTests, checkResumeAcquiresWakeLock)
{
using namespace ::testing;
- EXPECT_CALL(sharedWakelock, createWakelock()).Times(1);
+ EXPECT_CALL(sharedWakelock, acquire(_)).Times(1);
auto app = startApplication(123, "app");
auto session = app->session();
@@ -69,7 +69,7 @@ TEST_F(ApplicationTests, checkRespawnAcquiresWakeLock)
{
using namespace ::testing;
- EXPECT_CALL(sharedWakelock, createWakelock()).Times(1);
+ EXPECT_CALL(sharedWakelock, acquire(_)).Times(1);
const QString appId = "app";
auto app = startApplication(123, "app");
@@ -89,7 +89,7 @@ TEST_F(ApplicationTests, checkDashFocusDoesNotAcquireWakeLock)
{
using namespace ::testing;
- EXPECT_CALL(sharedWakelock, createWakelock()).Times(0);
+ EXPECT_CALL(sharedWakelock, acquire(_)).Times(0);
startApplication(123, "unity8-dash");
applicationManager.focusApplication("unity8-dash");
@@ -105,14 +105,14 @@ TEST_F(ApplicationTests, checkDashSuspendDoesNotImpactWakeLock)
applicationManager.focusApplication("unity8-dash");
Q_EMIT session->suspended();
- EXPECT_FALSE(sharedWakelock.wakelockHeld());
+ EXPECT_FALSE(sharedWakelock.enabled());
}
TEST_F(ApplicationTests, checkDashResumeDoesNotAcquireWakeLock)
{
using namespace ::testing;
- EXPECT_CALL(sharedWakelock, createWakelock()).Times(0);
+ EXPECT_CALL(sharedWakelock, acquire(_)).Times(0);
auto app = startApplication(123, "unity8-dash");
auto session = app->session();
diff --git a/tests/modules/ApplicationManager/application_manager_test.cpp b/tests/modules/ApplicationManager/application_manager_test.cpp
index bd6008a..fa73b81 100644
--- a/tests/modules/ApplicationManager/application_manager_test.cpp
+++ b/tests/modules/ApplicationManager/application_manager_test.cpp
@@ -15,6 +15,8 @@
*
*/
+#define MIR_INCLUDE_DEPRECATED_EVENT_HEADER
+
#include <thread>
#include <condition_variable>
#include <QSignalSpy>
@@ -2232,3 +2234,81 @@ TEST_F(ApplicationManagerTests, focusMainStageAfterSideStage)
.Times(0);
applicationManager.focusApplication(webbrowserAppId);
}
+
+/*
+ * Test lifecycle exempt applications have their wakelocks released when shell tries to suspend them
+ */
+TEST_F(ApplicationManagerTests,lifecycleExemptAppsHaveWakelockReleasedOnAttemptedSuspend)
+{
+ using namespace ::testing;
+
+ const QString appId("com.ubuntu.music"); // member of lifecycle exemption list
+ const quint64 procId = 12345;
+
+ // Set up Mocks & signal watcher
+ auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
+ ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
+ ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
+
+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
+
+ EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(appId, _))
+ .Times(1)
+ .WillOnce(Return(true));
+
+ auto application = applicationManager.startApplication(appId, ApplicationManager::NoFlag);
+ applicationManager.onProcessStarting(appId);
+ std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId);
+ bool authed = true;
+ applicationManager.authorizeSession(procId, authed);
+ onSessionStarting(session);
+
+ // App creates surface, focuses it so state is running
+ std::shared_ptr<mir::scene::Surface> surface(nullptr);
+ applicationManager.onSessionCreatedSurface(session.get(), surface);
+ applicationManager.focusApplication(appId);
+
+ applicationManager.unfocusCurrentApplication();
+
+ EXPECT_FALSE(sharedWakelock.enabled());
+ EXPECT_EQ(application->state(), Application::Running);
+}
+
+/*
+ * Test lifecycle exempt applications have their wakelocks released on suspend
+ */
+TEST_F(ApplicationManagerTests,lifecycleExemptAppsHaveWakelockReleasedOnUnSuspend)
+{
+ using namespace ::testing;
+
+ const QString appId("com.ubuntu.music"); // member of lifecycle exemption list
+ const quint64 procId = 12345;
+
+ // Set up Mocks & signal watcher
+ auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
+ ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
+ ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
+
+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
+
+ EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(appId, _))
+ .Times(1)
+ .WillOnce(Return(true));
+
+ auto application = applicationManager.startApplication(appId, ApplicationManager::NoFlag);
+ applicationManager.onProcessStarting(appId);
+ std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId);
+ bool authed = true;
+ applicationManager.authorizeSession(procId, authed);
+ onSessionStarting(session);
+
+ // App creates surface, focuses it so state is running
+ std::shared_ptr<mir::scene::Surface> surface(nullptr);
+ applicationManager.onSessionCreatedSurface(session.get(), surface);
+ applicationManager.focusApplication(appId);
+
+ applicationManager.setSuspended(true);
+
+ EXPECT_FALSE(sharedWakelock.enabled());
+ EXPECT_EQ(application->state(), Application::Running);
+}
diff --git a/tests/modules/MirSurfaceItem/mirsurfaceitem_test.cpp b/tests/modules/MirSurfaceItem/mirsurfaceitem_test.cpp
index 9fa237c..7d3b727 100644
--- a/tests/modules/MirSurfaceItem/mirsurfaceitem_test.cpp
+++ b/tests/modules/MirSurfaceItem/mirsurfaceitem_test.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 Canonical, Ltd.
+ * Copyright (C) 2014-2015 Canonical, Ltd.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License version 3, as published by
@@ -15,6 +15,8 @@
*
*/
+#define MIR_INCLUDE_DEPRECATED_EVENT_HEADER
+
#include <gtest/gtest.h>
#include <QLoggingCategory>
@@ -60,29 +62,43 @@ TEST(MirSurfaceItemTest, MissingTouchEnd)
EXPECT_CALL(*mockSurface, type()).Times(AnyNumber()).WillRepeatedly(Return(mir_surface_type_normal));
EXPECT_CALL(*mockSession, setSurface(_)).Times(AnyNumber());
+ auto getTouchEvent = [](MirEvent const& event) -> MirTouchInputEvent const*
+ {
+ if (mir_event_get_type(&event) != mir_event_type_input)
+ return nullptr;
+ auto const* input_event = mir_event_get_input_event(&event);
+ if (mir_input_event_get_type(input_event) != mir_input_event_type_touch)
+ return nullptr;
+ return mir_input_event_get_touch_input_event(input_event);
+ };
+
+ auto eventMatches = [&](MirEvent const& event,
+ int touch_count,
+ MirTouchInputEventTouchAction action,
+ MirTouchInputEventTouchId touch_id) ->void
+ {
+ auto const* touch_event = getTouchEvent(event);
+ ASSERT_NE(touch_event, nullptr);
+ ASSERT_EQ(touch_count, mir_touch_input_event_get_touch_count(touch_event));
+ ASSERT_EQ(action, mir_touch_input_event_get_touch_action(touch_event,0));
+ ASSERT_EQ(touch_id, mir_touch_input_event_get_touch_id(touch_event,0));
+ };
+
// The touch event sequence we expect mir::input::surface to receive from MirSurfaceItem.
// It should properly finish the sequence for touch 0 ('down', 'move' and 'up') before starting
// the sequence for touch 1.
EXPECT_CALL(*mockSurface, consume(_))
- .WillOnce(Invoke([] (MirEvent const& mirEvent) {
- ASSERT_EQ(mir_motion_action_down, mirEvent.motion.action);
- ASSERT_EQ(1, mirEvent.motion.pointer_count);
- ASSERT_EQ(0, mirEvent.motion.pointer_coordinates[0].id);
+ .WillOnce(Invoke([&] (MirEvent const& mirEvent) {
+ eventMatches(mirEvent, 1, mir_touch_input_event_action_down, 0);
}))
- .WillOnce(Invoke([] (MirEvent const& mirEvent) {
- ASSERT_EQ(mir_motion_action_move, mirEvent.motion.action);
- ASSERT_EQ(1, mirEvent.motion.pointer_count);
- ASSERT_EQ(0, mirEvent.motion.pointer_coordinates[0].id);
+ .WillOnce(Invoke([&] (MirEvent const& mirEvent) {
+ eventMatches(mirEvent, 1, mir_touch_input_event_action_change, 0);
}))
- .WillOnce(Invoke([] (MirEvent const& mirEvent) {
- ASSERT_EQ(mir_motion_action_up, mirEvent.motion.action);
- ASSERT_EQ(1, mirEvent.motion.pointer_count);
- ASSERT_EQ(0, mirEvent.motion.pointer_coordinates[0].id);
+ .WillOnce(Invoke([&] (MirEvent const& mirEvent) {
+ eventMatches(mirEvent, 1, mir_touch_input_event_action_up, 0);
}))
- .WillOnce(Invoke([] (MirEvent const& mirEvent) {
- ASSERT_EQ(mir_motion_action_down, mirEvent.motion.action);
- ASSERT_EQ(1, mirEvent.motion.pointer_count);
- ASSERT_EQ(1, mirEvent.motion.pointer_coordinates[0].id);
+ .WillOnce(Invoke([&] (MirEvent const& mirEvent) {
+ eventMatches(mirEvent, 1, mir_touch_input_event_action_down, 1);
}));
@@ -95,19 +111,19 @@ TEST(MirSurfaceItemTest, MissingTouchEnd)
touchPoints[0].setId(0);
touchPoints[0].setState(Qt::TouchPointPressed);
surfaceItem->processTouchEvent(QEvent::TouchBegin,
- timestamp, touchPoints, touchPoints[0].state());
+ timestamp, Qt::NoModifier, touchPoints, touchPoints[0].state());
touchPoints[0].setState(Qt::TouchPointMoved);
surfaceItem->processTouchEvent(QEvent::TouchUpdate,
- timestamp + 10, touchPoints, touchPoints[0].state());
+ timestamp + 10, Qt::NoModifier, touchPoints, touchPoints[0].state());
// Starting a new touch sequence (with touch 1) without ending the current one
// (wich has touch 0).
touchPoints[0].setId(1);
touchPoints[0].setState(Qt::TouchPointPressed);
surfaceItem->processTouchEvent(QEvent::TouchBegin,
- timestamp + 20, touchPoints, touchPoints[0].state());
-
+ timestamp + 20, Qt::NoModifier, touchPoints, touchPoints[0].state());
+
delete surfaceItem;
delete mockSession;
}
diff --git a/tests/modules/SharedWakelock/CMakeLists.txt b/tests/modules/SharedWakelock/CMakeLists.txt
index 99838a4..6dab098 100644
--- a/tests/modules/SharedWakelock/CMakeLists.txt
+++ b/tests/modules/SharedWakelock/CMakeLists.txt
@@ -6,6 +6,8 @@ set(
include_directories(
${CMAKE_SOURCE_DIR}/src/modules
${CMAKE_SOURCE_DIR}/tests/modules/common
+ ${QTDBUSTEST_INCLUDE_DIRS}
+ ${QTDBUSMOCK_INCLUDE_DIRS}
)
add_executable(sharedwakelock_test ${SHARED_WAKELOCK_TEST_SOURCES})
@@ -15,8 +17,12 @@ target_link_libraries(
unityapplicationplugin
+ Qt5::Test
+
${GTEST_BOTH_LIBRARIES}
${GMOCK_LIBRARIES}
+ ${QTDBUSTEST_LIBRARIES}
+ ${QTDBUSMOCK_LIBRARIES}
)
add_test(SharedWakelock, sharedwakelock_test)
diff --git a/tests/modules/SharedWakelock/sharedwakelock_test.cpp b/tests/modules/SharedWakelock/sharedwakelock_test.cpp
index 4242ee5..3ad5eba 100644
--- a/tests/modules/SharedWakelock/sharedwakelock_test.cpp
+++ b/tests/modules/SharedWakelock/sharedwakelock_test.cpp
@@ -17,154 +17,373 @@
#include <Unity/Application/sharedwakelock.h>
-#include "mock_shared_wakelock.h"
+#include <libqtdbusmock/DBusMock.h>
-#include <gmock/gmock.h>
+#include <QCoreApplication>
+#include <QSignalSpy>
#include <gtest/gtest.h>
using namespace qtmir;
-using testing::MockSharedWakelock;
+using namespace testing;
+using namespace QtDBusTest;
+using namespace QtDBusMock;
-TEST(SharedWakelock, acquireCreatesAWakelock)
+const char POWERD_NAME[] = "com.canonical.powerd";
+const char POWERD_PATH[] = "/com/canonical/powerd";
+const char POWERD_INTERFACE[] = "com.canonical.powerd";
+
+class SharedWakelockTest: public Test
+{
+protected:
+ SharedWakelockTest()
+ : mock(dbus)
+ {
+ mock.registerCustomMock(POWERD_NAME,
+ POWERD_PATH,
+ POWERD_INTERFACE,
+ QDBusConnection::SystemBus);
+
+ dbus.startServices();
+ }
+
+ virtual ~SharedWakelockTest()
+ {}
+
+ virtual OrgFreedesktopDBusMockInterface& powerdMockInterface()
+ {
+ return mock.mockInterface(POWERD_NAME,
+ POWERD_PATH,
+ POWERD_INTERFACE,
+ QDBusConnection::SystemBus);
+ }
+
+ void implementRequestSysState() {
+ // Defines the mock impementation of this DBus method
+ powerdMockInterface().AddMethod("com.canonical.powerd",
+ "requestSysState", "si", "s", "ret = 'cookie'").waitForFinished();
+ }
+
+ void implementClearSysState() {
+ powerdMockInterface().AddMethod("com.canonical.powerd",
+ "clearSysState", "s", "", "").waitForFinished();
+ }
+
+ void EXPECT_CALL(const QList<QVariantList> &spy, int index,
+ const QString &name, const QVariantList &args)
+ {
+ QVariant args2(QVariant::fromValue(args));
+ ASSERT_LT(index, spy.size());
+ const QVariantList &call(spy.at(index));
+ EXPECT_EQ(name, call.at(0).toString());
+ EXPECT_EQ(args2.toString().toStdString(), call.at(1).toString().toStdString());
+ }
+
+ DBusTestRunner dbus;
+ DBusMock mock;
+};
+
+TEST_F(SharedWakelockTest, acquireCreatesAWakelock)
+{
+ implementRequestSysState();
+
+ /* Note: we pass the DBusTestRunner constructed system DBus connection instead of letting
+ * Qt create one. This is done as Qt has a non-testing friendly way of handling the built-in
+ * system and session connections, and as DBusTestRunner restarts the DBus daemon for each
+ * testcase, it unfortunately means Qt would end up pointing to a dead bus after one testcase. */
+ SharedWakelock wakelock(dbus.systemConnection());
+
+ // Verify the DBus method is called & wakelock
+ QSignalSpy wakelockDBusMethodSpy(&powerdMockInterface(), SIGNAL(MethodCalled(const QString &, const QVariantList &)));
+ QSignalSpy wakelockEnabledSpy(&wakelock, SIGNAL( enabledChanged(bool) ));
+
+ QScopedPointer<QObject> object(new QObject);
+ wakelock.acquire(object.data());
+ wakelockDBusMethodSpy.wait();
+
+ EXPECT_FALSE(wakelockDBusMethodSpy.empty());
+ EXPECT_CALL(wakelockDBusMethodSpy, 0, "requestSysState",
+ QVariantList() << QString("active") << 1);
+
+ // Ensure a wakelock created
+ wakelockEnabledSpy.wait();
+ EXPECT_FALSE(wakelockEnabledSpy.empty());
+ EXPECT_TRUE(wakelock.enabled());
+}
+
+TEST_F(SharedWakelockTest, acquireThenReleaseDestroysTheWakelock)
{
- using namespace ::testing;
+ implementRequestSysState();
+ implementClearSysState();
+
+ SharedWakelock wakelock(dbus.systemConnection());
- testing::NiceMock<MockSharedWakelock> sharedWakelock;
- QScopedPointer<QObject> app1(new QObject);
+ QSignalSpy wakelockEnabledSpy(&wakelock, SIGNAL( enabledChanged(bool) ));
- EXPECT_CALL(sharedWakelock, createWakelock()).Times(1);
- sharedWakelock.acquire(app1.data());
+ QScopedPointer<QObject> object(new QObject);
+ wakelock.acquire(object.data());
+ wakelockEnabledSpy.wait();
+
+ // Verify the DBus method is called
+ QSignalSpy wakelockDBusMethodSpy(&powerdMockInterface(), SIGNAL(MethodCalled(const QString &, const QVariantList &)));
+ wakelock.release(object.data());
+ wakelockDBusMethodSpy.wait();
+
+ EXPECT_FALSE(wakelockDBusMethodSpy.empty());
+ EXPECT_CALL(wakelockDBusMethodSpy, 0, "clearSysState",
+ QVariantList() << QString("cookie"));
+
+ EXPECT_FALSE(wakelock.enabled());
}
-TEST(SharedWakelock, acquireThenReleaseDestroysTheWakelock)
+TEST_F(SharedWakelockTest, doubleAcquireBySameOwnerOnlyCreatesASingleWakelock)
{
- using namespace ::testing;
+ implementRequestSysState();
+
+ SharedWakelock wakelock(dbus.systemConnection());
+
+ // Verify the DBus method is called & wakelock
+ QSignalSpy wakelockDBusMethodSpy(&powerdMockInterface(), SIGNAL(MethodCalled(const QString &, const QVariantList &)));
- testing::NiceMock<MockSharedWakelock> sharedWakelock;
- QScopedPointer<QObject> app1(new QObject);
+ QScopedPointer<QObject> object(new QObject);
+ wakelock.acquire(object.data());
+ wakelock.acquire(object.data());
+ wakelockDBusMethodSpy.wait();
- sharedWakelock.acquire(app1.data());
- sharedWakelock.release(app1.data());
- EXPECT_FALSE(sharedWakelock.wakelockHeld());
+ EXPECT_EQ(wakelockDBusMethodSpy.count(), 1);
}
-TEST(SharedWakelock, doubleAcquireBySameOwnerOnlyCreatesASingleWakelock)
+TEST_F(SharedWakelockTest, doubleAcquireThenReleaseBySameOwnerDestroysWakelock)
{
- using namespace ::testing;
+ implementRequestSysState();
+ implementClearSysState();
- testing::NiceMock<MockSharedWakelock> sharedWakelock;
- QScopedPointer<QObject> app1(new QObject);
+ SharedWakelock wakelock(dbus.systemConnection());
- EXPECT_CALL(sharedWakelock, createWakelock()).Times(1).WillOnce(Return(new QObject));
- sharedWakelock.acquire(app1.data());
- sharedWakelock.acquire(app1.data());
+ QSignalSpy wakelockEnabledSpy(&wakelock, SIGNAL( enabledChanged(bool) ));
+ QScopedPointer<QObject> object(new QObject);
+
+ wakelock.acquire(object.data());
+ wakelock.acquire(object.data());
+ wakelock.release(object.data());
+ wakelockEnabledSpy.wait();
+ EXPECT_FALSE(wakelock.enabled());
}
-TEST(SharedWakelock, doubleAcquireThenReleaseBySameOwnerDestroysWakelock)
+TEST_F(SharedWakelockTest, acquireByDifferentOwnerOnlyCreatesASingleWakelock)
{
- using namespace ::testing;
+ implementRequestSysState();
+
+ SharedWakelock wakelock(dbus.systemConnection());
+
+ // Verify the DBus method is called & wakelock
+ QSignalSpy wakelockDBusMethodSpy(&powerdMockInterface(), SIGNAL(MethodCalled(const QString &, const QVariantList &)));
- testing::NiceMock<MockSharedWakelock> sharedWakelock;
- QScopedPointer<QObject> app1(new QObject);
+ QScopedPointer<QObject> object1(new QObject);
+ QScopedPointer<QObject> object2(new QObject);
+ wakelock.acquire(object1.data());
+ wakelock.acquire(object2.data());
- EXPECT_CALL(sharedWakelock, createWakelock()).Times(1).WillOnce(Return(new QObject));
- sharedWakelock.acquire(app1.data());
- sharedWakelock.acquire(app1.data());
- sharedWakelock.release(app1.data());
- EXPECT_FALSE(sharedWakelock.wakelockHeld());
+ wakelockDBusMethodSpy.wait();
+ EXPECT_EQ(wakelockDBusMethodSpy.count(), 1);
}
-TEST(SharedWakelock, acquireByDifferentOwnerOnlyCreatesASingleWakelock)
+TEST_F(SharedWakelockTest, twoOwnersWhenBothReleaseWakelockReleased)
{
- using namespace ::testing;
+ implementRequestSysState();
+
+ SharedWakelock wakelock(dbus.systemConnection());
+
+ QScopedPointer<QObject> object1(new QObject);
+ QScopedPointer<QObject> object2(new QObject);
+ wakelock.acquire(object1.data());
+ wakelock.acquire(object2.data());
- testing::NiceMock<MockSharedWakelock> sharedWakelock;
- QScopedPointer<QObject> app1(new QObject);
- QScopedPointer<QObject> app2(new QObject);
+ QSignalSpy wakelockEnabledSpy(&wakelock, SIGNAL( enabledChanged(bool) ));
- EXPECT_CALL(sharedWakelock, createWakelock()).Times(1).WillOnce(Return(new QObject));
- sharedWakelock.acquire(app1.data());
- sharedWakelock.acquire(app2.data());
+ wakelock.release(object1.data());
+ wakelock.release(object2.data());
+
+ wakelockEnabledSpy.wait();
+ EXPECT_FALSE(wakelock.enabled());
}
-TEST(SharedWakelock, twoOwnersWhenOneReleasesStillHoldWakelock)
+TEST_F(SharedWakelockTest, doubleReleaseOfSingleOwnerIgnored)
{
- using namespace ::testing;
+ implementRequestSysState();
+
+ SharedWakelock wakelock(dbus.systemConnection());
+
+ QSignalSpy wakelockEnabledSpy(&wakelock, SIGNAL( enabledChanged(bool) ));
+
+ QScopedPointer<QObject> object1(new QObject);
+ QScopedPointer<QObject> object2(new QObject);
+ wakelock.acquire(object1.data());
+ wakelock.acquire(object2.data());
+ wakelock.release(object1.data());
+
+ wakelockEnabledSpy.wait();
- testing::NiceMock<MockSharedWakelock> sharedWakelock;
- QScopedPointer<QObject> app1(new QObject);
- QScopedPointer<QObject> app2(new QObject);
+ wakelock.release(object1.data());
- EXPECT_CALL(sharedWakelock, createWakelock()).Times(1).WillOnce(Return(new QObject));
- sharedWakelock.acquire(app1.data());
- sharedWakelock.acquire(app2.data());
- sharedWakelock.release(app1.data());
- EXPECT_TRUE(sharedWakelock.wakelockHeld());
+ EXPECT_TRUE(wakelock.enabled());
}
-TEST(SharedWakelock, twoOwnersWhenBothReleaseWakelockReleased)
+TEST_F(SharedWakelockTest, wakelockAcquireReleaseFlood)
{
- using namespace ::testing;
-
- testing::NiceMock<MockSharedWakelock> sharedWakelock;
- QScopedPointer<QObject> app1(new QObject);
- QScopedPointer<QObject> app2(new QObject);
-
- EXPECT_CALL(sharedWakelock, createWakelock()).Times(1).WillOnce(Return(new QObject));
- sharedWakelock.acquire(app1.data());
- sharedWakelock.acquire(app2.data());
- sharedWakelock.release(app2.data());
- sharedWakelock.release(app1.data());
- EXPECT_FALSE(sharedWakelock.wakelockHeld());
+ implementRequestSysState();
+ implementClearSysState();
+
+ SharedWakelock wakelock(dbus.systemConnection());
+
+ QSignalSpy wakelockEnabledSpy(&wakelock, SIGNAL( enabledChanged(bool) ));
+
+ QScopedPointer<QObject> object(new QObject);
+ wakelock.acquire(object.data());
+ wakelock.release(object.data());
+ wakelock.acquire(object.data());
+ wakelock.release(object.data());
+ wakelock.acquire(object.data());
+ wakelock.release(object.data());
+ while (wakelockEnabledSpy.wait(100)) {}
+ EXPECT_FALSE(wakelock.enabled());
}
-TEST(SharedWakelock, doubleReleaseOfSingleOwnerIgnored)
+TEST_F(SharedWakelockTest, wakelockAcquireReleaseAcquireWithDelays)
{
- using namespace ::testing;
+ powerdMockInterface().AddMethod("com.canonical.powerd",
+ "requestSysState", "si", "s",
+ "i=100000\n" // delay the response from the mock dbus instance
+ "while i>0:\n"
+ " i-=1\n"
+ "ret = 'cookie'").waitForFinished();
+
+ implementClearSysState();
+
+ SharedWakelock wakelock(dbus.systemConnection());
+
+ QSignalSpy wakelockDBusMethodSpy(&powerdMockInterface(), SIGNAL(MethodCalled(const QString &, const QVariantList &)));
+
+ QScopedPointer<QObject> object(new QObject);
+ wakelock.acquire(object.data());
+ wakelock.release(object.data());
+ wakelock.acquire(object.data());
+
+ while (wakelockDBusMethodSpy.wait()) {}
+ EXPECT_TRUE(wakelock.enabled());
+
+ // there must be at least one clearSysState call, but is not necessarily the second call
+ // should the dbus response be slow enough, it may be the third call. Is hard to reliably
+ // reproduce the racey condition for all platforms.
+ bool found = false;
+ for (int i=0; i<wakelockDBusMethodSpy.count(); i++) {
+ const QVariantList &call(wakelockDBusMethodSpy.at(i));
+
+ if (call.at(0).toString() == "clearSysState") {
+ found = true;
+ }
+ }
+ EXPECT_TRUE(found);
+}
+
+TEST_F(SharedWakelockTest, nullOwnerAcquireIgnored)
+{
+ implementRequestSysState();
+
+ SharedWakelock wakelock(dbus.systemConnection());
+
+ QSignalSpy wakelockEnabledSpy(&wakelock, SIGNAL( enabledChanged(bool) ));
- testing::NiceMock<MockSharedWakelock> sharedWakelock;
- QScopedPointer<QObject> app1(new QObject);
- QScopedPointer<QObject> app2(new QObject);
+ wakelock.acquire(nullptr);
- EXPECT_CALL(sharedWakelock, createWakelock()).Times(1).WillOnce(Return(new QObject));
- sharedWakelock.acquire(app1.data());
- sharedWakelock.acquire(app2.data());
- sharedWakelock.release(app1.data());
- EXPECT_TRUE(sharedWakelock.wakelockHeld());
+ wakelockEnabledSpy.wait(200); // have to wait to see if anything happens
- sharedWakelock.release(app1.data());
- EXPECT_TRUE(sharedWakelock.wakelockHeld());
+ EXPECT_FALSE(wakelock.enabled());
}
-TEST(SharedWakelock, nullOwnerAcquireIgnored)
+TEST_F(SharedWakelockTest, nullReleaseAcquireIgnored)
{
- using namespace ::testing;
+ implementRequestSysState();
- testing::NiceMock<MockSharedWakelock> sharedWakelock;
+ SharedWakelock wakelock(dbus.systemConnection());
- EXPECT_CALL(sharedWakelock, createWakelock()).Times(0);
- sharedWakelock.acquire(nullptr);
+ wakelock.release(nullptr);
+
+ EXPECT_FALSE(wakelock.enabled());
}
-TEST(SharedWakelock, nullOwnerReleaseIgnored)
+TEST_F(SharedWakelockTest, ifOwnerDestroyedWakelockReleased)
{
- using namespace ::testing;
+ implementRequestSysState();
+ implementClearSysState();
+
+ SharedWakelock wakelock(dbus.systemConnection());
+
+ QSignalSpy wakelockEnabledSpy(&wakelock, SIGNAL( enabledChanged(bool) ));
+
+ QScopedPointer<QObject> object(new QObject);
+ wakelock.acquire(object.data());
+ wakelockEnabledSpy.wait();
+
+ // Verify the DBus method is called
+ QSignalSpy wakelockDBusMethodSpy(&powerdMockInterface(), SIGNAL(MethodCalled(const QString &, const QVariantList &)));
- testing::NiceMock<MockSharedWakelock> sharedWakelock;
+ object.reset();
+ wakelockDBusMethodSpy.wait();
- EXPECT_CALL(sharedWakelock, createWakelock()).Times(0);
- sharedWakelock.release(nullptr);
+ EXPECT_FALSE(wakelockDBusMethodSpy.empty());
+ EXPECT_CALL(wakelockDBusMethodSpy, 0, "clearSysState",
+ QVariantList() << QString("cookie"));
+
+ EXPECT_FALSE(wakelock.enabled());
}
-TEST(SharedWakelock, ifOwnerDestroyedWakelockReleased)
+TEST_F(SharedWakelockTest, reloadCachedWakelockCookie)
{
- using namespace ::testing;
+ const char cookieFile[] = "/tmp/qtmir_powerd_cookie";
+
+ // Custom Deleter for QScopedPointer to delete the qtmir cookie file no matter what
+ struct ScopedQFileCustomDeleter
+ {
+ static inline void cleanup(QFile *file)
+ {
+ file->remove();
+ delete file;
+ }
+ };
+ QScopedPointer<QFile, ScopedQFileCustomDeleter> cookieCache(new QFile(cookieFile));
+ cookieCache->open(QFile::WriteOnly | QFile::Text);
+ cookieCache->write("myCookie");
+
+ SharedWakelock wakelock(dbus.systemConnection());
+ EXPECT_TRUE(wakelock.enabled());
+}
+
+TEST_F(SharedWakelockTest, wakelockReleasedOnSharedWakelockDestroyed)
+{
+ implementRequestSysState();
+ implementClearSysState();
+
+ auto wakelock = new SharedWakelock(dbus.systemConnection());
+
+ QSignalSpy wakelockEnabledSpy(wakelock, SIGNAL( enabledChanged(bool) ));
+
+ QScopedPointer<QObject> object(new QObject);
+ wakelock->acquire(object.data());
+ wakelockEnabledSpy.wait(); // wait for wakelock to be enabled
+
+ QSignalSpy wakelockDBusMethodSpy(&powerdMockInterface(), SIGNAL(MethodCalled(const QString &, const QVariantList &)));
+ delete wakelock;
+ wakelockDBusMethodSpy.wait();
+
+ EXPECT_FALSE(wakelockDBusMethodSpy.empty());
+ EXPECT_CALL(wakelockDBusMethodSpy, 0, "clearSysState",
+ QVariantList() << QString("cookie"));
+}
- testing::NiceMock<MockSharedWakelock> sharedWakelock;
- QScopedPointer<QObject> app1(new QObject);
- EXPECT_CALL(sharedWakelock, createWakelock()).Times(1).WillOnce(Return(new QObject));
- sharedWakelock.acquire(app1.data());
- app1.reset();
- EXPECT_FALSE(sharedWakelock.wakelockHeld());
+// Define custom main() as these tests rely on a QEventLoop
+int main(int argc, char** argv) {
+ QCoreApplication app(argc, argv);
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
}
diff --git a/tests/modules/common/mock_shared_wakelock.h b/tests/modules/common/mock_shared_wakelock.h
index 78d3281..0e99a53 100644
--- a/tests/modules/common/mock_shared_wakelock.h
+++ b/tests/modules/common/mock_shared_wakelock.h
@@ -23,21 +23,48 @@
namespace testing
{
-struct MockSharedWakelock : public qtmir::SharedWakelock
+class MockSharedWakelock : public qtmir::SharedWakelock
{
- MockSharedWakelock()
+public:
+ MockSharedWakelock(const QDBusConnection& /*connection*/= QDBusConnection::systemBus())
{
- ON_CALL(*this, createWakelock()).WillByDefault(Invoke(this, &MockSharedWakelock::doCreateWakelock));
+ ON_CALL(*this, enabled()).WillByDefault(Invoke(this, &MockSharedWakelock::doEnabled));
+ ON_CALL(*this, acquire(_)).WillByDefault(Invoke(this, &MockSharedWakelock::doAcquire));
+ ON_CALL(*this, release(_)).WillByDefault(Invoke(this, &MockSharedWakelock::doRelease));
}
- MOCK_METHOD0(createWakelock, QObject*());
- bool wakelockHeld() { return m_wakelock; }
+ MOCK_CONST_METHOD0(enabled, bool());
+ MOCK_METHOD1(acquire, void(const QObject *));
+ MOCK_METHOD1(release, void(const QObject *));
+ bool doEnabled()
+ {
+ return !m_owners.isEmpty();
+ }
+
+ void doAcquire(const QObject *object)
+ {
+ if (m_owners.contains(object)) {
+ return;
+ }
+ m_owners.insert(object);
+ if (m_owners.size() == 1) {
+ Q_EMIT enabledChanged(true);
+ }
+ }
- QObject* doCreateWakelock() const
+ void doRelease(const QObject *object)
{
- return new QObject;
+ if (!m_owners.remove(object)) {
+ return;
+ }
+ if (m_owners.isEmpty()) {
+ Q_EMIT enabledChanged(false);
+ }
}
+
+private:
+ QSet<const QObject *> m_owners;
};
} // namespace testing