2
* Copyright © 2015 Canonical Ltd.
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License version 3 as
6
* published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16
* Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
19
#include "src/unity_screen_service.h"
20
#include "src/dbus_connection_handle.h"
21
#include "src/dbus_message_handle.h"
22
#include "src/screen.h"
23
#include "src/power_state_change_reason.h"
24
#include "src/unity_screen_service_introspection.h"
25
#include "wait_condition.h"
27
#include "dbus_client.h"
29
#include <gtest/gtest.h>
30
#include <gmock/gmock.h>
35
namespace ut = usc::test;
40
struct MockScreen : usc::Screen
42
MOCK_METHOD1(enable_inactivity_timers, void(bool enable));
43
MOCK_METHOD1(toggle_screen_power_mode, void(PowerStateChangeReason reason));
44
MOCK_METHOD0(keep_display_on_temporarily, void());
46
MOCK_METHOD2(set_screen_power_mode, void(MirPowerMode mode, PowerStateChangeReason reason));
47
MOCK_METHOD1(keep_display_on, void(bool on));
48
MOCK_METHOD1(set_brightness, void(int brightness));
49
MOCK_METHOD1(enable_auto_brightness, void(bool enable));
50
MOCK_METHOD2(set_inactivity_timeouts, void(int power_off_timeout, int dimmer_timeout));
52
MOCK_METHOD1(set_touch_visualization_enabled, void(bool enabled));
54
void register_power_state_change_handler(
55
usc::PowerStateChangeHandler const& handler)
57
power_state_change_handler = handler;
60
usc::PowerStateChangeHandler power_state_change_handler;
63
class UnityScreenDBusClient : public ut::DBusClient
66
UnityScreenDBusClient(std::string const& address)
69
"com.canonical.Unity.Screen",
70
"/com/canonical/Unity/Screen"}
74
"interface='com.canonical.Unity.Screen',"
75
"member='DisplayPowerStateChange'");
78
ut::DBusAsyncReplyString request_introspection()
80
return invoke_with_reply<ut::DBusAsyncReplyString>(
81
"org.freedesktop.DBus.Introspectable", "Introspect",
85
ut::DBusAsyncReplyVoid request_set_user_brightness(int32_t brightness)
87
return invoke_with_reply<ut::DBusAsyncReplyVoid>(
88
unity_screen_interface, "setUserBrightness",
89
DBUS_TYPE_INT32, &brightness,
93
ut::DBusAsyncReplyVoid request_user_auto_brightness_enable(bool enabled)
95
dbus_bool_t const e = enabled ? TRUE : FALSE;
96
return invoke_with_reply<ut::DBusAsyncReplyVoid>(
97
unity_screen_interface, "userAutobrightnessEnable",
98
DBUS_TYPE_BOOLEAN, &e,
102
ut::DBusAsyncReplyVoid request_set_inactivity_timeouts(
103
int32_t poweroff_timeout, int32_t dimmer_timeout)
105
return invoke_with_reply<ut::DBusAsyncReplyVoid>(
106
unity_screen_interface, "setInactivityTimeouts",
107
DBUS_TYPE_INT32, &poweroff_timeout,
108
DBUS_TYPE_INT32, &dimmer_timeout,
112
ut::DBusAsyncReplyVoid request_set_touch_visualization_enabled(bool enabled)
114
dbus_bool_t const e = enabled ? TRUE : FALSE;
115
return invoke_with_reply<ut::DBusAsyncReplyVoid>(
116
unity_screen_interface, "setTouchVisualizationEnabled",
117
DBUS_TYPE_BOOLEAN, &e,
121
ut::DBusAsyncReplyBool request_set_screen_power_mode(
122
std::string const& mode, int reason)
124
auto mode_cstr = mode.c_str();
125
return invoke_with_reply<ut::DBusAsyncReplyBool>(
126
unity_screen_interface, "setScreenPowerMode",
127
DBUS_TYPE_STRING, &mode_cstr,
128
DBUS_TYPE_INT32, &reason,
132
ut::DBusAsyncReplyInt request_keep_display_on()
134
return invoke_with_reply<ut::DBusAsyncReplyInt>(
135
unity_screen_interface, "keepDisplayOn",
139
ut::DBusAsyncReplyVoid request_remove_display_on_request(int id)
141
return invoke_with_reply<ut::DBusAsyncReplyVoid>(
142
unity_screen_interface, "removeDisplayOnRequest",
143
DBUS_TYPE_INT32, &id,
147
ut::DBusAsyncReply request_invalid_method()
149
return invoke_with_reply<ut::DBusAsyncReply>(
150
unity_screen_interface, "invalidMethod",
154
ut::DBusAsyncReply request_method_with_invalid_arguments()
156
char const* const str = "abcd";
157
return invoke_with_reply<ut::DBusAsyncReply>(
158
unity_screen_interface, "setUserBrightness",
159
DBUS_TYPE_STRING, &str,
163
usc::DBusMessageHandle listen_for_power_state_change_signal()
167
dbus_connection_read_write(connection, 1);
168
auto msg = usc::DBusMessageHandle{dbus_connection_pop_message(connection)};
170
if (msg && dbus_message_is_signal(msg, "com.canonical.Unity.Screen", "DisplayPowerStateChange"))
177
char const* const unity_screen_interface = "com.canonical.Unity.Screen";
180
struct AUnityScreenService : testing::Test
182
std::chrono::seconds const default_timeout{3};
185
std::shared_ptr<MockScreen> const mock_screen =
186
std::make_shared<testing::NiceMock<MockScreen>>();
187
UnityScreenDBusClient client{bus.address()};
188
usc::UnityScreenService service{bus.address(), mock_screen};
193
TEST_F(AUnityScreenService, replies_to_introspection_request)
195
using namespace testing;
197
auto reply = client.request_introspection();
198
EXPECT_THAT(reply.get(), Eq(unity_screen_service_introspection));
201
TEST_F(AUnityScreenService, forwards_set_user_brightness_request)
203
int const brightness = 10;
205
EXPECT_CALL(*mock_screen, set_brightness(brightness));
207
client.request_set_user_brightness(brightness);
210
TEST_F(AUnityScreenService, forwards_user_auto_brightness_enable_request)
212
bool const enable = true;
214
EXPECT_CALL(*mock_screen, enable_auto_brightness(enable));
216
client.request_user_auto_brightness_enable(enable);
219
TEST_F(AUnityScreenService, forwards_set_inactivity_timeouts_request)
221
int const poweroff_timeout = 1000;
222
int const dimmer_timeout = 500;
224
EXPECT_CALL(*mock_screen, set_inactivity_timeouts(poweroff_timeout, dimmer_timeout));
226
client.request_set_inactivity_timeouts(poweroff_timeout, dimmer_timeout);
229
TEST_F(AUnityScreenService, forwards_set_touch_visualization_enabled_request)
231
bool const enabled = true;
233
EXPECT_CALL(*mock_screen, set_touch_visualization_enabled(enabled));
235
client.request_set_touch_visualization_enabled(enabled);
238
TEST_F(AUnityScreenService, forwards_set_screen_power_mode_request)
240
auto const mode = MirPowerMode::mir_power_mode_standby;
241
std::string const mode_str = "standby";
242
auto const reason = PowerStateChangeReason::proximity;
243
auto const reason_int = static_cast<int>(reason);
245
EXPECT_CALL(*mock_screen, set_screen_power_mode(mode, reason));
247
client.request_set_screen_power_mode(mode_str, reason_int);
250
TEST_F(AUnityScreenService, replies_to_set_screen_power_mode_request)
252
using namespace testing;
254
std::string const mode_str = "standby";
255
auto const reason_int = static_cast<int>(PowerStateChangeReason::proximity);
257
auto reply = client.request_set_screen_power_mode(mode_str, reason_int);
259
EXPECT_THAT(reply.get(), Eq(true));
262
TEST_F(AUnityScreenService, forwards_keep_display_on_request)
264
EXPECT_CALL(*mock_screen, keep_display_on(true));
266
client.request_keep_display_on();
269
TEST_F(AUnityScreenService, replies_with_different_ids_to_keep_display_on_requests)
271
using namespace testing;
273
auto reply1 = client.request_keep_display_on();
274
auto reply2 = client.request_keep_display_on();
276
auto const id1 = reply1.get();
277
auto const id2 = reply2.get();
279
EXPECT_THAT(id1, Ne(id2));
282
TEST_F(AUnityScreenService, disables_keep_display_on_when_single_request_is_removed)
284
using namespace testing;
287
EXPECT_CALL(*mock_screen, keep_display_on(true));
288
EXPECT_CALL(*mock_screen, keep_display_on(false));
290
auto reply1 = client.request_keep_display_on();
291
client.request_remove_display_on_request(reply1.get());
294
TEST_F(AUnityScreenService, disables_keep_display_on_when_all_requests_are_removed)
296
using namespace testing;
298
EXPECT_CALL(*mock_screen, keep_display_on(true)).Times(3);
299
EXPECT_CALL(*mock_screen, keep_display_on(false)).Times(0);
301
auto reply1 = client.request_keep_display_on();
302
auto reply2 = client.request_keep_display_on();
303
auto reply3 = client.request_keep_display_on();
305
client.request_remove_display_on_request(reply1.get());
306
client.request_remove_display_on_request(reply2.get());
307
auto id3 = reply3.get();
309
// Display should still be kept on at this point
310
Mock::VerifyAndClearExpectations(mock_screen.get());
312
// keep_display_on should be disable only when the last request is removed
313
EXPECT_CALL(*mock_screen, keep_display_on(false));
315
client.request_remove_display_on_request(id3);
318
TEST_F(AUnityScreenService, disables_keep_display_on_when_single_client_disconnects)
320
ut::WaitCondition request_processed;
322
EXPECT_CALL(*mock_screen, keep_display_on(true)).Times(3);
323
EXPECT_CALL(*mock_screen, keep_display_on(false))
324
.WillOnce(WakeUp(&request_processed));
326
client.request_keep_display_on();
327
client.request_keep_display_on();
328
client.request_keep_display_on();
332
request_processed.wait_for(default_timeout);
333
EXPECT_TRUE(request_processed.woken());
336
TEST_F(AUnityScreenService, disables_keep_display_on_when_all_clients_disconnect_or_remove_requests)
338
using namespace testing;
340
UnityScreenDBusClient other_client{bus.address()};
342
EXPECT_CALL(*mock_screen, keep_display_on(true)).Times(4);
343
EXPECT_CALL(*mock_screen, keep_display_on(false)).Times(0);
345
auto reply1 = client.request_keep_display_on();
346
auto reply2 = client.request_keep_display_on();
347
other_client.request_keep_display_on();
348
other_client.request_keep_display_on();
350
other_client.disconnect();
351
client.request_remove_display_on_request(reply1.get());
352
auto id2 = reply2.get();
354
// Display should still be kept on at this point
355
Mock::VerifyAndClearExpectations(mock_screen.get());
357
// keep_display_on should be disabled only when the last request is removed
358
ut::WaitCondition request_processed;
359
EXPECT_CALL(*mock_screen, keep_display_on(false))
360
.WillOnce(WakeUp(&request_processed));
362
client.request_remove_display_on_request(id2);
364
request_processed.wait_for(default_timeout);
365
EXPECT_TRUE(request_processed.woken());
368
TEST_F(AUnityScreenService, emits_power_state_change_signal)
370
using namespace testing;
372
auto async_message = std::async(std::launch::async,
373
[&] { return client.listen_for_power_state_change_signal(); });
375
mock_screen->power_state_change_handler(
376
MirPowerMode::mir_power_mode_off, PowerStateChangeReason::power_key);
378
auto message = async_message.get();
382
dbus_message_get_args(message, nullptr,
383
DBUS_TYPE_INT32, &state,
384
DBUS_TYPE_INT32, &reason,
387
int32_t const off_state{0};
389
EXPECT_THAT(state, Eq(off_state));
390
EXPECT_THAT(reason, Eq(static_cast<int32_t>(PowerStateChangeReason::power_key)));
393
TEST_F(AUnityScreenService, returns_error_reply_for_unsupported_method)
395
using namespace testing;
397
auto reply = client.request_invalid_method();
398
auto reply_msg = reply.get();
400
EXPECT_THAT(dbus_message_get_type(reply_msg), Eq(DBUS_MESSAGE_TYPE_ERROR));
401
EXPECT_THAT(dbus_message_get_error_name(reply_msg), StrEq(DBUS_ERROR_FAILED));
404
TEST_F(AUnityScreenService, returns_error_reply_for_method_with_invalid_arguments)
406
using namespace testing;
408
auto reply = client.request_method_with_invalid_arguments();
409
auto reply_msg = reply.get();
411
EXPECT_THAT(dbus_message_get_type(reply_msg), Eq(DBUS_MESSAGE_TYPE_ERROR));
412
EXPECT_THAT(dbus_message_get_error_name(reply_msg), StrEq(DBUS_ERROR_FAILED));