2
* Copyright © 2014 Canonical Ltd.
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,
6
* as 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 "mir_toolkit/mir_screencast.h"
20
#include "mir_toolkit/mir_client_library.h"
22
#include "mir_test_framework/stubbed_server_configuration.h"
23
#include "mir_test_framework/in_process_server.h"
24
#include "mir_test_framework/using_stub_client_platform.h"
25
#include "src/server/frontend/protobuf_ipc_factory.h"
26
#include "mir_protobuf.pb.h"
28
#include "mir_test_doubles/null_display_changer.h"
29
#include "mir_test_doubles/stub_display_configuration.h"
30
#include "mir_test/fake_shared.h"
32
#include <gtest/gtest.h>
33
#include <gmock/gmock.h>
35
namespace mtf = mir_test_framework;
36
namespace mtd = mir::test::doubles;
37
namespace mg = mir::graphics;
38
namespace mf = mir::frontend;
39
namespace mt = mir::test;
49
MATCHER_P(WithOutputId, value, "")
51
return arg->output_id() == value;
54
MATCHER_P(WithScreencastId, value, "")
56
return arg->value() == value;
59
ACTION_P(SetCreateScreencastId, screencast_id)
61
arg2->mutable_screencast_id()->set_value(screencast_id);
64
ACTION(FillCreateScreencastBuffer)
68
FAIL() << "Failed to create FillCreateScreencastBuffer fds";
70
arg2->mutable_buffer()->add_fd(fds[0]);
74
* This setup is used temporarily to test MirScreencast, until
75
* we have the server-side implementation of the feature in place.
77
struct MockScreencastServer : mir::protobuf::DisplayServer
80
std::shared_ptr<mir::protobuf::DisplayServer> const& ds)
81
: wrapped_display_server{ds}
83
using namespace testing;
84
ON_CALL(*this, create_screencast(_,_,_,_))
85
.WillByDefault(DoAll(FillCreateScreencastBuffer(),RunClosure()));
86
ON_CALL(*this, release_screencast(_,_,_,_))
87
.WillByDefault(RunClosure());
91
::google::protobuf::RpcController* rpc,
92
const ::mir::protobuf::ConnectParameters* request,
93
::mir::protobuf::Connection* response,
94
::google::protobuf::Closure* done) override
96
wrapped_display_server->connect(rpc, request, response, done);
100
google::protobuf::RpcController* rpc,
101
const mir::protobuf::Void* request,
102
mir::protobuf::Void* response,
103
google::protobuf::Closure* done) override
105
wrapped_display_server->disconnect(rpc, request, response, done);
108
MOCK_METHOD4(create_screencast,
109
void(google::protobuf::RpcController*,
110
const mir::protobuf::ScreencastParameters*,
111
mir::protobuf::Screencast*,
112
google::protobuf::Closure*));
114
MOCK_METHOD4(release_screencast,
115
void(google::protobuf::RpcController*,
116
const mir::protobuf::ScreencastId*,
117
mir::protobuf::Void*,
118
google::protobuf::Closure*));
120
std::shared_ptr<mir::protobuf::DisplayServer> const wrapped_display_server;
123
std::shared_ptr<MockScreencastServer> global_mock_screencast_server;
125
class WrappingIpcFactory : public mf::ProtobufIpcFactory
129
std::shared_ptr<mf::ProtobufIpcFactory> const& ipc_factory)
130
: wrapped_ipc_factory{ipc_factory}
134
std::shared_ptr<mir::protobuf::DisplayServer> make_ipc_server(
135
std::shared_ptr<mf::EventSink> const& sink, bool auth) override
137
auto ipc_server = wrapped_ipc_factory->make_ipc_server(sink, auth);
138
global_mock_screencast_server =
139
std::make_shared<testing::NiceMock<MockScreencastServer>>(ipc_server);
140
return global_mock_screencast_server;
143
std::shared_ptr<mf::ResourceCache> resource_cache() override
145
return wrapped_ipc_factory->resource_cache();
149
std::shared_ptr<mf::ProtobufIpcFactory> const wrapped_ipc_factory;
152
class StubChanger : public mtd::NullDisplayChanger
156
: stub_display_config{{{connected, !used}, {connected, used}}}
160
std::shared_ptr<mg::DisplayConfiguration> active_configuration() override
162
return mt::fake_shared(stub_display_config);
165
mtd::StubDisplayConfig stub_display_config;
168
static bool const connected;
169
static bool const used;
172
bool const StubChanger::connected{true};
173
bool const StubChanger::used{true};
175
struct StubServerConfig : mir_test_framework::StubbedServerConfiguration
177
std::shared_ptr<mf::DisplayChanger> the_frontend_display_changer() override
179
return mt::fake_shared(stub_changer);
182
std::shared_ptr<mf::ProtobufIpcFactory> the_ipc_factory(
183
std::shared_ptr<mf::Shell> const& shell,
184
std::shared_ptr<mg::GraphicBufferAllocator> const& alloc) override
186
auto factory = mtf::StubbedServerConfiguration::the_ipc_factory(shell, alloc);
187
return std::make_shared<WrappingIpcFactory>(factory);
190
StubChanger stub_changer;
193
class MirScreencastTest : public mir_test_framework::InProcessServer
198
global_mock_screencast_server.reset();
201
mir::DefaultServerConfiguration& server_config() override { return server_config_; }
203
StubServerConfig server_config_;
204
mtf::UsingStubClientPlatform using_stub_client_platform;
209
TEST_F(MirScreencastTest, creation_with_invalid_connection_fails)
211
using namespace testing;
213
uint32_t const output_id{2};
214
MirScreencastParameters params{output_id, 0, 0, mir_pixel_format_invalid};
216
auto screencast = mir_connection_create_screencast_sync(nullptr, ¶ms);
217
ASSERT_EQ(nullptr, screencast);
220
TEST_F(MirScreencastTest, creation_with_invalid_output_fails)
222
using namespace testing;
224
auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
225
ASSERT_TRUE(mir_connection_is_valid(connection));
227
uint32_t const invalid_output_id{33};
228
MirScreencastParameters params{invalid_output_id, 0, 0, mir_pixel_format_invalid};
230
EXPECT_CALL(*global_mock_screencast_server,
231
create_screencast(_,_,_,_))
235
mir_connection_create_screencast_sync(connection, ¶ms);
236
ASSERT_EQ(nullptr, screencast);
238
mir_connection_release(connection);
241
TEST_F(MirScreencastTest, create_and_release_contact_server)
243
using namespace testing;
245
auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
246
ASSERT_TRUE(mir_connection_is_valid(connection));
248
uint32_t const screencast_id{99};
249
uint32_t const output_id{2};
250
MirScreencastParameters params{output_id, 0, 0, mir_pixel_format_invalid};
254
EXPECT_CALL(*global_mock_screencast_server,
255
create_screencast(_,WithOutputId(output_id),_,_))
256
.WillOnce(DoAll(SetCreateScreencastId(screencast_id),
257
FillCreateScreencastBuffer(),
260
EXPECT_CALL(*global_mock_screencast_server,
261
release_screencast(_,WithScreencastId(screencast_id),_,_))
262
.WillOnce(RunClosure());
264
auto screencast = mir_connection_create_screencast_sync(connection, ¶ms);
265
ASSERT_NE(nullptr, screencast);
266
mir_screencast_release_sync(screencast);
268
mir_connection_release(connection);
271
TEST_F(MirScreencastTest, gets_valid_egl_native_window)
273
using namespace testing;
275
auto const connection = mir_connect_sync(new_connection().c_str(), __PRETTY_FUNCTION__);
276
ASSERT_TRUE(mir_connection_is_valid(connection));
278
uint32_t const output_id{2};
279
MirScreencastParameters params{output_id, 0, 0, mir_pixel_format_invalid};
281
auto screencast = mir_connection_create_screencast_sync(connection, ¶ms);
282
ASSERT_NE(nullptr, screencast);
284
auto egl_native_window = mir_screencast_egl_native_window(screencast);
285
EXPECT_NE(MirEGLNativeWindowType(), egl_native_window);
287
mir_screencast_release_sync(screencast);
289
mir_connection_release(connection);