1 // Copyright 2010-2018, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "renderer/renderer_client.h"
31
32 #include <string>
33
34 #include "base/logging.h"
35 #include "base/number_util.h"
36 #include "base/port.h"
37 #include "base/util.h"
38 #include "base/version.h"
39 #include "ipc/ipc.h"
40 #include "protocol/renderer_command.pb.h"
41 #include "renderer/renderer_interface.h"
42 #include "testing/base/public/gunit.h"
43
44 namespace mozc {
45
46 namespace renderer {
47
48 namespace {
UpdateVersion(int diff)49 const string UpdateVersion(int diff) {
50 std::vector<string> tokens;
51 Util::SplitStringUsing(Version::GetMozcVersion(), ".", &tokens);
52 EXPECT_EQ(tokens.size(), 4);
53 char buf[64];
54 snprintf(buf, sizeof(buf), "%d", NumberUtil::SimpleAtoi(tokens[3]) + diff);
55 tokens[3] = buf;
56 string output;
57 Util::JoinStrings(tokens, ".", &output);
58 return output;
59 }
60
61 int g_counter = 0;
62 bool g_connected = false;
63 uint32 g_server_protocol_version = IPC_PROTOCOL_VERSION;
64 string g_server_product_version;
65
66 class TestIPCClient : public IPCClientInterface {
67 public:
TestIPCClient()68 TestIPCClient() {
69 g_server_product_version = Version::GetMozcVersion();
70 }
~TestIPCClient()71 ~TestIPCClient() {}
72
Connected() const73 bool Connected() const {
74 return g_connected;
75 }
76
GetServerProtocolVersion() const77 uint32 GetServerProtocolVersion() const {
78 return g_server_protocol_version;
79 }
80
GetServerProductVersion() const81 const string &GetServerProductVersion() const {
82 return g_server_product_version;
83 }
84
85
GetServerProcessId() const86 uint32 GetServerProcessId() const {
87 return 0;
88 }
89
90 // just count up how many times Call is called.
Call(const char * request,size_t request_size,char * response,size_t * response_size,int32 timeout)91 virtual bool Call(const char *request,
92 size_t request_size,
93 char *response,
94 size_t *response_size,
95 int32 timeout) {
96 g_counter++;
97 return true;
98 }
99
set_connected(bool connected)100 static void set_connected(bool connected) {
101 g_connected = connected;
102 }
103
Reset()104 static void Reset() {
105 g_counter = 0;
106 }
107
counter()108 static int counter() {
109 return g_counter;
110 }
111
set_server_protocol_version(uint32 version)112 static void set_server_protocol_version(uint32 version) {
113 g_server_protocol_version = version;
114 }
115
GetLastIPCError() const116 virtual IPCErrorType GetLastIPCError() const {
117 return IPC_NO_ERROR;
118 }
119 };
120
121 class TestIPCClientFactory : public IPCClientFactoryInterface {
122 public:
TestIPCClientFactory()123 TestIPCClientFactory() {}
~TestIPCClientFactory()124 ~TestIPCClientFactory() {}
125
NewClient(const string & name,const string & path_name)126 virtual IPCClientInterface *NewClient(const string &name,
127 const string &path_name) {
128 return new TestIPCClient;
129 }
130
NewClient(const string & name)131 virtual IPCClientInterface *NewClient(const string &name) {
132 return new TestIPCClient;
133 }
134 };
135
136 class TestRendererLauncher : public RendererLauncherInterface {
137 public:
TestRendererLauncher()138 TestRendererLauncher()
139 : start_renderer_called_(false),
140 force_terminate_renderer_called_(false),
141 available_(false), can_connect_(false) {}
~TestRendererLauncher()142 ~TestRendererLauncher() {}
143
144 // implement StartServer.
145 // return true if server can launched successfully.
StartRenderer(const string & name,const string & renderer_path,bool disable_renderer_path_check,IPCClientFactoryInterface * ipc_client_factory_interface)146 void StartRenderer(const string &name,
147 const string &renderer_path,
148 bool disable_renderer_path_check,
149 IPCClientFactoryInterface *ipc_client_factory_interface) {
150 start_renderer_called_ = true;
151 LOG(INFO) << name << " " << renderer_path;
152 }
153
ForceTerminateRenderer(const string & name)154 bool ForceTerminateRenderer(const string &name) {
155 force_terminate_renderer_called_ = true;
156 return true;
157 }
158
OnFatal(RendererErrorType type)159 void OnFatal(RendererErrorType type) {
160 LOG(ERROR) << static_cast<int>(type);
161 }
162
163 // return true if the renderer is running
IsAvailable() const164 virtual bool IsAvailable() const {
165 return available_;
166 }
167
168 // return true if client can make a IPC connection.
CanConnect() const169 virtual bool CanConnect() const {
170 return can_connect_;
171 }
172
SetPendingCommand(const commands::RendererCommand & command)173 virtual void SetPendingCommand(
174 const commands::RendererCommand &command) {
175 set_pending_command_called_ = true;
176 }
177
set_suppress_error_dialog(bool suppress)178 virtual void set_suppress_error_dialog(bool suppress) {
179 }
180
Reset()181 void Reset() {
182 start_renderer_called_ = false;
183 force_terminate_renderer_called_ = false;
184 available_ = false;
185 can_connect_ = false;
186 set_pending_command_called_ = false;
187 }
188
set_available(bool available)189 void set_available(bool available) {
190 available_ = available;
191 }
192
set_can_connect(bool can_connect)193 void set_can_connect(bool can_connect) {
194 can_connect_ = can_connect;
195 }
196
is_start_renderer_called() const197 bool is_start_renderer_called() const {
198 return start_renderer_called_;
199 }
200
is_force_terminate_renderer_called() const201 bool is_force_terminate_renderer_called() const {
202 return force_terminate_renderer_called_;
203 }
204
is_set_pending_command_called() const205 bool is_set_pending_command_called() const {
206 return set_pending_command_called_;
207 }
208
209 private:
210 bool start_renderer_called_;
211 bool force_terminate_renderer_called_;
212 bool available_;
213 bool can_connect_;
214 bool set_pending_command_called_;
215 };
216 } // namespace
217
TEST(RendererClient,InvalidTest)218 TEST(RendererClient, InvalidTest) {
219 RendererClient client;
220
221 client.SetIPCClientFactory(NULL);
222 client.SetRendererLauncherInterface(NULL);
223 commands::RendererCommand command;
224
225 // IPCClientFactory and Launcher must be set.
226 EXPECT_FALSE(client.ExecCommand(command));
227 EXPECT_FALSE(client.IsAvailable());
228 EXPECT_FALSE(client.Activate());
229 }
230
TEST(RendererClient,ActivateTest)231 TEST(RendererClient, ActivateTest) {
232 TestIPCClientFactory factory;
233 TestRendererLauncher launcher;
234
235 RendererClient client;
236
237 client.SetIPCClientFactory(&factory);
238 client.SetRendererLauncherInterface(&launcher);
239
240 {
241 launcher.set_available(true);
242 EXPECT_TRUE(client.IsAvailable());
243 launcher.set_available(false);
244 EXPECT_FALSE(client.IsAvailable());
245 }
246
247 {
248 // No connection may happen if can_connect is false
249 launcher.set_available(false);
250 launcher.set_can_connect(false);
251 TestIPCClient::Reset();
252 EXPECT_TRUE(client.Activate());
253 EXPECT_EQ(0, TestIPCClient::counter());
254 }
255
256 {
257 // No connection may happen if connected return false
258 launcher.set_available(false);
259 launcher.set_can_connect(true);
260 TestIPCClient::set_connected(false);
261 TestIPCClient::Reset();
262 EXPECT_TRUE(client.Activate());
263 EXPECT_EQ(0, TestIPCClient::counter());
264 }
265
266 {
267 // one IPC call happens
268 launcher.set_available(false);
269 launcher.set_can_connect(true);
270 TestIPCClient::set_connected(true);
271 TestIPCClient::Reset();
272 EXPECT_TRUE(client.Activate());
273 EXPECT_EQ(1, TestIPCClient::counter());
274 }
275
276 {
277 // once launcher is available, no IPC call happens
278 // with Activate()
279 launcher.set_available(true);
280 TestIPCClient::Reset();
281 EXPECT_TRUE(client.Activate());
282 EXPECT_TRUE(client.Activate());
283 EXPECT_TRUE(client.Activate());
284 EXPECT_EQ(0, TestIPCClient::counter());
285 }
286 }
287
TEST(RendererClient,LaunchTest)288 TEST(RendererClient, LaunchTest) {
289 TestIPCClientFactory factory;
290 TestRendererLauncher launcher;
291
292 RendererClient client;
293
294 client.SetIPCClientFactory(&factory);
295 client.SetRendererLauncherInterface(&launcher);
296
297 commands::RendererCommand command;
298 command.mutable_output()->set_id(0);
299 command.set_type(commands::RendererCommand::NOOP);
300
301 {
302 // if can connect is false,
303 // renderer is not launched
304 launcher.Reset();
305 launcher.set_can_connect(false);
306 TestIPCClient::set_connected(false);
307 EXPECT_TRUE(client.ExecCommand(command));
308 EXPECT_FALSE(launcher.is_start_renderer_called());
309 }
310
311 {
312 // if connection is not available, start renderer process
313 launcher.Reset();
314 launcher.set_can_connect(true);
315 TestIPCClient::set_connected(false);
316 command.set_visible(true);
317 EXPECT_TRUE(client.ExecCommand(command));
318 EXPECT_TRUE(launcher.is_start_renderer_called());
319 }
320
321 {
322 // if connection is not available,
323 // but the command type is HIDE, renderer is not launched
324 launcher.Reset();
325 launcher.set_can_connect(true);
326 TestIPCClient::set_connected(false);
327 command.set_visible(false);
328 command.set_type(commands::RendererCommand::UPDATE);
329 EXPECT_TRUE(client.ExecCommand(command));
330 EXPECT_FALSE(launcher.is_start_renderer_called());
331 }
332
333 {
334 command.set_type(commands::RendererCommand::NOOP);
335 // if every state is OK, renderer is not launched
336 launcher.Reset();
337 launcher.set_can_connect(true);
338 TestIPCClient::set_connected(true);
339 command.set_visible(true);
340 EXPECT_TRUE(client.ExecCommand(command));
341 EXPECT_TRUE(client.ExecCommand(command));
342 EXPECT_TRUE(client.ExecCommand(command));
343 EXPECT_FALSE(launcher.is_start_renderer_called());
344 }
345 }
346
TEST(RendererClient,ConnectionTest)347 TEST(RendererClient, ConnectionTest) {
348 TestIPCClientFactory factory;
349 TestRendererLauncher launcher;
350
351 RendererClient client;
352
353 client.SetIPCClientFactory(&factory);
354 client.SetRendererLauncherInterface(&launcher);
355
356 commands::RendererCommand command;
357 command.set_type(commands::RendererCommand::NOOP);
358
359 {
360 launcher.Reset();
361 launcher.set_can_connect(true);
362 TestIPCClient::set_connected(true);
363 TestIPCClient::Reset();
364 EXPECT_TRUE(client.ExecCommand(command));
365 EXPECT_TRUE(client.ExecCommand(command));
366 EXPECT_TRUE(client.ExecCommand(command));
367
368 // IPC should be called three times
369 EXPECT_EQ(3, TestIPCClient::counter());
370 }
371
372 {
373 // launcher denies connection
374 launcher.Reset();
375 launcher.set_can_connect(false);
376 TestIPCClient::set_connected(true);
377 TestIPCClient::Reset();
378 EXPECT_TRUE(client.ExecCommand(command));
379 EXPECT_TRUE(client.ExecCommand(command));
380 EXPECT_TRUE(client.ExecCommand(command));
381 EXPECT_EQ(0, TestIPCClient::counter());
382 }
383
384 {
385 // IPC connection is lost.
386 launcher.Reset();
387 launcher.set_can_connect(true);
388 TestIPCClient::set_connected(false);
389 TestIPCClient::Reset();
390 EXPECT_TRUE(client.ExecCommand(command));
391 EXPECT_TRUE(client.ExecCommand(command));
392 EXPECT_TRUE(client.ExecCommand(command));
393 EXPECT_EQ(0, TestIPCClient::counter());
394 }
395 }
396
TEST(RendererClient,ShutdownTest)397 TEST(RendererClient, ShutdownTest) {
398 TestIPCClientFactory factory;
399 TestRendererLauncher launcher;
400
401 RendererClient client;
402
403 client.SetIPCClientFactory(&factory);
404 client.SetRendererLauncherInterface(&launcher);
405
406 {
407 launcher.Reset();
408 launcher.set_can_connect(true);
409 TestIPCClient::set_connected(true);
410 TestIPCClient::Reset();
411
412 // Shutdown with commands::RendererCommand::SHUTDOWN command
413 EXPECT_TRUE(client.Shutdown(false));
414 EXPECT_FALSE(launcher.is_force_terminate_renderer_called());
415 EXPECT_EQ(1, TestIPCClient::counter());
416 }
417
418 {
419 launcher.Reset();
420 launcher.set_can_connect(true);
421 TestIPCClient::set_connected(true);
422 TestIPCClient::Reset();
423
424 // Shutdown with ForceTerminateRenderer
425 EXPECT_TRUE(client.Shutdown(true));
426 EXPECT_TRUE(launcher.is_force_terminate_renderer_called());
427 EXPECT_EQ(0, TestIPCClient::counter());
428 }
429
430 {
431 launcher.Reset();
432 launcher.set_can_connect(false);
433 TestIPCClient::set_connected(false);
434 TestIPCClient::Reset();
435
436 EXPECT_TRUE(client.Shutdown(false));
437 EXPECT_FALSE(launcher.is_force_terminate_renderer_called());
438 EXPECT_EQ(0, TestIPCClient::counter());
439 }
440
441 {
442 launcher.Reset();
443 launcher.set_can_connect(false);
444 TestIPCClient::set_connected(false);
445 TestIPCClient::Reset();
446
447 EXPECT_TRUE(client.Shutdown(true));
448 EXPECT_FALSE(launcher.is_force_terminate_renderer_called());
449 EXPECT_EQ(0, TestIPCClient::counter());
450 }
451 }
452
TEST(RendererClient,ProtocolVersionMismatchNewer)453 TEST(RendererClient, ProtocolVersionMismatchNewer) {
454 TestIPCClientFactory factory;
455 TestRendererLauncher launcher;
456
457 RendererClient client;
458
459 client.SetIPCClientFactory(&factory);
460 client.SetRendererLauncherInterface(&launcher);
461
462 commands::RendererCommand command;
463 command.set_type(commands::RendererCommand::NOOP);
464
465 {
466 launcher.Reset();
467 launcher.set_can_connect(true);
468 TestIPCClient::set_connected(true);
469 TestIPCClient::Reset();
470 TestIPCClient::set_server_protocol_version(IPC_PROTOCOL_VERSION - 1);
471 EXPECT_TRUE(client.ExecCommand(command));
472 EXPECT_TRUE(launcher.is_force_terminate_renderer_called());
473 EXPECT_EQ(0, TestIPCClient::counter());
474 }
475 }
476
TEST(RendererClient,ProtocolVersionMismatchOlder)477 TEST(RendererClient, ProtocolVersionMismatchOlder) {
478 TestIPCClientFactory factory;
479 TestRendererLauncher launcher;
480
481 RendererClient client;
482
483 client.SetIPCClientFactory(&factory);
484 client.SetRendererLauncherInterface(&launcher);
485
486 commands::RendererCommand command;
487 command.set_type(commands::RendererCommand::NOOP);
488
489 {
490 launcher.Reset();
491 launcher.set_can_connect(true);
492 TestIPCClient::set_connected(true);
493 TestIPCClient::Reset();
494 TestIPCClient::set_server_protocol_version(IPC_PROTOCOL_VERSION + 1);
495 EXPECT_TRUE(client.ExecCommand(command));
496 EXPECT_FALSE(launcher.is_force_terminate_renderer_called());
497 EXPECT_EQ(0, TestIPCClient::counter());
498 }
499 }
500
TEST(RendererClient,MozcVersionMismatchNewer)501 TEST(RendererClient, MozcVersionMismatchNewer) {
502 TestIPCClientFactory factory;
503 TestRendererLauncher launcher;
504
505 RendererClient client;
506
507 client.SetIPCClientFactory(&factory);
508 client.SetRendererLauncherInterface(&launcher);
509
510 commands::RendererCommand command;
511 command.set_type(commands::RendererCommand::NOOP);
512 g_server_product_version = UpdateVersion(-1);
513
514 {
515 launcher.Reset();
516 launcher.set_can_connect(true);
517 TestIPCClient::set_connected(true);
518 TestIPCClient::Reset();
519 TestIPCClient::set_server_protocol_version(IPC_PROTOCOL_VERSION);
520 EXPECT_TRUE(client.ExecCommand(command));
521 EXPECT_FALSE(launcher.is_force_terminate_renderer_called());
522 EXPECT_EQ(1, TestIPCClient::counter());
523 }
524 }
525
TEST(RendererClient,MozcVersionMismatchOlder)526 TEST(RendererClient, MozcVersionMismatchOlder) {
527 TestIPCClientFactory factory;
528 TestRendererLauncher launcher;
529
530 RendererClient client;
531
532 client.SetIPCClientFactory(&factory);
533 client.SetRendererLauncherInterface(&launcher);
534
535 commands::RendererCommand command;
536 command.set_type(commands::RendererCommand::NOOP);
537 g_server_product_version = UpdateVersion(1);
538
539 {
540 launcher.Reset();
541 launcher.set_can_connect(true);
542 TestIPCClient::set_connected(true);
543 TestIPCClient::Reset();
544 TestIPCClient::set_server_protocol_version(IPC_PROTOCOL_VERSION);
545 EXPECT_TRUE(client.ExecCommand(command));
546 EXPECT_FALSE(launcher.is_force_terminate_renderer_called());
547 EXPECT_EQ(1, TestIPCClient::counter());
548 }
549 }
550
TEST(RendererClient,SetPendingCommandTest)551 TEST(RendererClient, SetPendingCommandTest) {
552 TestIPCClientFactory factory;
553 TestRendererLauncher launcher;
554
555 RendererClient client;
556
557 client.SetIPCClientFactory(&factory);
558 client.SetRendererLauncherInterface(&launcher);
559
560 commands::RendererCommand command;
561 command.set_type(commands::RendererCommand::NOOP);
562
563 {
564 launcher.Reset();
565 launcher.set_can_connect(true);
566 TestIPCClient::set_connected(false);
567 command.set_visible(true);
568 EXPECT_TRUE(client.ExecCommand(command));
569 EXPECT_TRUE(launcher.is_start_renderer_called());
570 EXPECT_TRUE(launcher.is_set_pending_command_called());
571 }
572
573 {
574 launcher.Reset();
575 launcher.set_can_connect(false);
576 TestIPCClient::set_connected(false);
577 command.set_visible(true);
578 EXPECT_TRUE(client.ExecCommand(command));
579 EXPECT_TRUE(launcher.is_set_pending_command_called());
580 }
581
582 {
583 launcher.Reset();
584 launcher.set_can_connect(true);
585 TestIPCClient::set_connected(true);
586 command.set_visible(true);
587 EXPECT_TRUE(client.ExecCommand(command));
588 EXPECT_FALSE(launcher.is_set_pending_command_called());
589 }
590 }
591 } // namespace renderer
592 } // namespace mozc
593