test_client.cpp
Go to the documentation of this file.
1 /*
2  * Unit tests for XmlRpc++
3  *
4  * Copyright (C) 2017, Zoox Inc
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  * Author: Austin Hendrix <austin@zoox.com>
21  *
22  */
23 
24 #define protected public
25 #include "xmlrpcpp/XmlRpcClient.h"
26 #undef protected
27 #include "xmlrpcpp/XmlRpcValue.h"
28 
29 #include "mock_socket.h"
30 #include <errno.h>
31 
32 #include <gtest/gtest.h>
33 
36 
37 namespace XmlRpc {
39  ::std::ostream* os) {
41 }
42 }; // namespace XmlRpc
43 
44 // Helper function to check if our source is in the dispatch source list or not.
47  XmlRpc::XmlRpcDispatch::SourceList::const_iterator itr;
48  for (itr = list.begin(); itr != list.end(); itr++) {
49  if (itr->getSource() == source) {
50  return true;
51  }
52  }
53  return false;
54 }
55 
56 // Tests for XmlRpcClient
57 //
58 // Test connectionStateStr macro
59 TEST(XmlRpcClient, connectionStateStr) {
60 #define TEST_STATE(state) \
61  EXPECT_STREQ(#state, XmlRpcClient::connectionStateStr(XmlRpcClient::state))
62  TEST_STATE(NO_CONNECTION);
63  TEST_STATE(CONNECTING);
64  TEST_STATE(WRITE_REQUEST);
65  TEST_STATE(READ_HEADER);
66  TEST_STATE(READ_RESPONSE);
67  TEST_STATE(IDLE);
68 }
69 
70 // Test state of client once constructor is done, including optional URL arg.
71 TEST_F(MockSocketTest, constructor) {
72  XmlRpcClient a("localhost", 42);
73  EXPECT_EQ("localhost", a._host);
74  EXPECT_EQ(42, a._port);
75  EXPECT_EQ("/RPC2", a._uri);
76 
78  EXPECT_EQ(false, a._executing);
79  EXPECT_EQ(false, a._eof);
80  EXPECT_EQ(true, a.getKeepOpen());
81  EXPECT_EQ(-1, a.getfd());
82  EXPECT_EQ(0, a._sendAttempts);
83  EXPECT_EQ(0, a._bytesWritten);
84  EXPECT_EQ(0, a._contentLength);
85  EXPECT_FALSE(a._isFault);
86  EXPECT_FALSE(sourceInList(&a, a._disp._sources));
87 
88  XmlRpcClient b("nowhere.com", 404, "/where");
89  EXPECT_EQ("nowhere.com", b._host);
90  EXPECT_EQ(404, b._port);
91  EXPECT_EQ("/where", b._uri);
92  // Don't really need to repeat the tests for the other variables.
93 }
94 
95 // Test close() function:
96 // * Does not call close when socket is already closed.
97 TEST_F(MockSocketTest, close_invalid_fd) {
98  XmlRpcClient a("localhost", 42);
99 
100  ASSERT_EQ(-1, a.getfd());
101 
102  // Close when no file descriptor is set
103  a.close();
104  EXPECT_EQ(-1, a.getfd());
105 }
106 
107 // Test close() function:
108 // * Correctly calls close when socket is not closed.
109 TEST_F(MockSocketTest, close_valid_fd) {
110  XmlRpcClient a("localhost", 42);
111 
112  // Set file descriptor and then expect that close is called once.
113  a.setfd(5);
114  Expect_close(5);
115  a.close();
116  EXPECT_EQ(-1, a.getfd());
117 
118  // Intermediate check that all expected calls have been executed.
119  CheckCalls();
120 
121  // Calling close again should have no effect.
122  a.close();
123  EXPECT_EQ(-1, a.getfd());
124 }
125 
126 TEST_F(MockSocketTest, close_destructor) {
127  // Test that the XmlRpcClient destructor closes the file descriptor.
128  {
129  XmlRpcClient a("localhost", 42);
130 
131  // Set file descriptor and then expect that close is called once.
132  a.setfd(5);
133  Expect_close(5);
134  // XmlRpcClient destructor called at the end of this scope.
135  }
136 }
137 
138 // Test execute() function? TODO(future work)
139 // This is a bit complicated; maybe test the underlying functions and then
140 // mock them out for this test.
141 // Test exectuteNonBlock() function? TODO(future work)
142 // Again, complicated. Maybe test underlying functions.
143 // Test executeCheckDone() ? TODO(future work)
144 // Complicated. There are known bugs here where the client never reports done
145 // if the connection is lost; we should try to test that logic.
146 // Test handleEvent() TODO(future work)
147 // For each ConnectionState
148 // The correct sequence of socket functions is called.
149 // The correct action is taken if the socket operations fail.
150 
151 // Test setupConnection()
152 // Correct handling of initial states.
153 // Correct handling of errors.
154 TEST_F(MockSocketTest, setupConnection) {
155  XmlRpcClient a("localhost", 42);
156 
157  // Default initial state; expect socket, setNonBlocking and connect.
158  // NOTE(austin): This does not currently expect these calls in order; it just
159  // checks that all of them have been made.
160  Expect_socket(7);
161  Expect_setNonBlocking(7, true);
162  Expect_connect(7, "localhost", 42, true);
163 
164  EXPECT_TRUE(a.setupConnection());
165 
166  // Check that correct FD was set.
167  EXPECT_EQ(7, a.getfd());
168 
169  // Check that source is in the dispatch source list now.
170  EXPECT_TRUE(sourceInList(&a, a._disp._sources));
171 
172  // Check internal state is reset.
174  EXPECT_EQ(0, a._bytesWritten);
175  CheckCalls();
176 
177  Expect_close(7);
178 }
179 
180 TEST_F(MockSocketTest, setupConnection_eof) {
181  XmlRpcClient a("localhost", 42);
182 
183  // Initial state: file descriptor set, but _eof. Expect close and socket,
184  // setNonBlocking, connect.
185  a.setfd(5);
186  a._eof = true;
187  Expect_close(5);
188 
189  Expect_socket(7);
190  Expect_setNonBlocking(7, true);
191  Expect_connect(7, "localhost", 42, true);
192 
193  EXPECT_TRUE(a.setupConnection());
194 
195  // Check that correct FD was set.
196  EXPECT_EQ(7, a.getfd());
197 
198  // Check that source is in the dispatch source list now.
199  EXPECT_TRUE(sourceInList(&a, a._disp._sources));
200 
201  // Check internal state is reset.
203  EXPECT_EQ(0, a._bytesWritten);
204  CheckCalls();
205 
206  Expect_close(7);
207 }
208 
209 TEST_F(MockSocketTest, setupConnection_close) {
210  XmlRpcClient a("localhost", 42);
211 
212  // Initial state: file descriptor set, but _eof
213  // NOTE(austin): Having multiple variables that imply that the fd is valid
214  // smells funny.
215  a.setfd(5);
217  Expect_close(5);
218 
219  Expect_socket(7);
220  Expect_setNonBlocking(7, true);
221  Expect_connect(7, "localhost", 42, true);
222 
223  EXPECT_TRUE(a.setupConnection());
224 
225  // Check that correct FD was set.
226  EXPECT_EQ(7, a.getfd());
227 
228  // Check that source is in the dispatch source list now.
229  EXPECT_TRUE(sourceInList(&a, a._disp._sources));
230 
231  // Check internal state is reset.
233  EXPECT_EQ(0, a._bytesWritten);
234  CheckCalls();
235 
236  Expect_close(7);
237 }
238 
239 TEST_F(MockSocketTest, setupConnection_err) {
240  XmlRpcClient a("localhost", 42);
241 
242  // Connect failure. Any failure that causes doConnect here will do; we choose
243  // an arbitrary failure mode here and then separately test that doConnect
244  // reports failure correctly in a separate set of tests.
245  Expect_socket(7);
246  Expect_setNonBlocking(7, true);
247  Expect_connect(7, "localhost", 42, false);
248  Expect_getError(ECONNREFUSED);
249  Expect_close(7);
250 
251  EXPECT_FALSE(a.setupConnection());
252 
253  // Check that FD is not set.
254  EXPECT_EQ(-1, a.getfd());
255 
256  // Check that source is not in the dispatch source list now.
257  EXPECT_FALSE(sourceInList(&a, a._disp._sources));
258 
259  // Check internal state is NO_CONNECTION
261 }
262 
263 // Check that _disp is left in the correct state after closing and then failing
264 // to reopen the socket.
265 TEST_F(MockSocketTest, setupConnection_eor_reopen) {
266  XmlRpcClient a("localhost", 42);
267 
268  // Default initial state; expect socket, setNonBlocking and connect.
269  // NOTE(austin): This does not currently expect these calls in order; it just
270  // checks that all of them have been made.
271  Expect_socket(7);
272  Expect_setNonBlocking(7, true);
273  Expect_connect(7, "localhost", 42, true);
274 
275  EXPECT_TRUE(a.setupConnection());
276 
277  // Check that correct FD was set.
278  EXPECT_EQ(7, a.getfd());
279 
280  // Check that source is in the dispatch source list now.
281  EXPECT_TRUE(sourceInList(&a, a._disp._sources));
282 
283  // Check internal state is reset.
285  EXPECT_EQ(0, a._bytesWritten);
286  CheckCalls();
287 
288  // Simulate socket encountering EOF
289  a._eof = true;
290 
291  // Expect close, socket, setNonBlocking and connect. Make connect fail.
292  Expect_close(7);
293  Expect_socket(8);
294  Expect_setNonBlocking(8, true);
295  Expect_connect(8, "localhost", 42, false);
296  Expect_getError(ECONNREFUSED);
297  Expect_close(8);
298 
299  EXPECT_FALSE(a.setupConnection());
300 
301  // Check that correct FD was set.
302  EXPECT_EQ(-1, a.getfd());
303 
304  // Check that source is no longer in the dispatch source list now.
305  EXPECT_FALSE(sourceInList(&a, a._disp._sources));
306 
307  // Check internal state is reset.
309  CheckCalls();
310 }
311 
312 // Test doConnect()
313 // Correct sequence of calls to XmlRpcSocket
314 // Correct handling of socket errors.
315 TEST_F(MockSocketTest, doConnect) {
316  XmlRpcClient a("localhost", 42);
317 
318  // Expect that socket, setNonBlocking and connect are called.
319  // NOTE(austin): this doesn't enforce ordering.
320  Expect_socket(7);
321  Expect_setNonBlocking(7, true);
322  Expect_connect(7, "localhost", 42, true);
323 
324  EXPECT_TRUE(a.doConnect());
325 
326  // Check that correct FD was set.
327  EXPECT_EQ(7, a.getfd());
328 
329  // Check that the expected calls have happened.
330  CheckCalls();
331 
332  // Expect close on destruction.
333  Expect_close(7);
334 }
335 
336 TEST_F(MockSocketTest, doConnect_socketerr) {
337  XmlRpcClient a("localhost", 42);
338 
339  Expect_socket(-1);
340  Expect_getError(ENFILE);
341 
342  EXPECT_FALSE(a.doConnect());
343 
344  // Check that correct FD was set.
345  EXPECT_EQ(-1, a.getfd());
346 }
347 
348 TEST_F(MockSocketTest, doConnect_nonBlockErr) {
349  XmlRpcClient a("localhost", 42);
350 
351  // Expect that setNonBlocking causes the socket to be closed and getError to
352  // be called.
353  Expect_socket(7);
354  Expect_setNonBlocking(7, false);
355  Expect_getError(EBADF);
356  Expect_close(7);
357 
358  EXPECT_FALSE(a.doConnect());
359 
360  // Check that correct FD was set.
361  EXPECT_EQ(-1, a.getfd());
362 }
363 
364 TEST_F(MockSocketTest, doConnect_connectErr) {
365  XmlRpcClient a("localhost", 42);
366 
367  // Expect that a connection failure causes the socket to be closed.
368  Expect_socket(7);
369  Expect_setNonBlocking(7, true);
370  Expect_connect(7, "localhost", 42, false);
371  Expect_getError(ECONNREFUSED);
372  Expect_close(7);
373 
374  EXPECT_FALSE(a.doConnect());
375 
376  // Check that correct FD was set.
377  EXPECT_EQ(-1, a.getfd());
378 }
379 
380 // Test generateRequest()
381 // Correct XML is generated for a variety of request types.
382 // Correct XML is generated for empty request
383 TEST(XmlRpcClient, generateRequest) {
384  XmlRpcClient a("localhost", 42);
385  // generateRequest takes a method name and params and puts the result in the
386  // _request member variable.
387  std::string header = "POST /RPC2 HTTP/1.1\r\n"
388  "User-Agent: XMLRPC++ 0.7\r\n"
389  "Host: localhost:42\r\n"
390  "Content-Type: text/xml\r\n";
391 
392  // Various tests for the nominal case of a normal XmlRpcValue
393  XmlRpcValue s("Hello");
394  EXPECT_TRUE(a.generateRequest("DoFoo", s));
395  EXPECT_EQ(header + "Content-length: 134\r\n\r\n"
396  "<?xml version=\"1.0\"?>\r\n"
397  "<methodCall><methodName>DoFoo</methodName>\r\n"
398  "<params><param><value>Hello</value></param></params></"
399  "methodCall>\r\n",
400  a._request);
401 
402  XmlRpcValue b(true);
403  EXPECT_TRUE(a.generateRequest("DoFoo", b));
404  EXPECT_EQ(header + "Content-length: 149\r\n\r\n"
405  "<?xml version=\"1.0\"?>\r\n"
406  "<methodCall><methodName>DoFoo</methodName>\r\n"
407  "<params><param><value><boolean>1</boolean></value></"
408  "param></params></methodCall>\r\n",
409  a._request);
410 
411  XmlRpcValue i(42);
412  EXPECT_TRUE(a.generateRequest("DoFoo", i));
413  EXPECT_EQ(header + "Content-length: 140\r\n\r\n"
414  "<?xml version=\"1.0\"?>\r\n"
415  "<methodCall><methodName>DoFoo</methodName>\r\n"
416  "<params><param><value><i4>42</i4></value></param></"
417  "params></methodCall>\r\n",
418  a._request);
419 
420  // Array case is a bit special because it results in emitting multiple
421  // <param> tags.
422  XmlRpcValue arr;
423  arr[0] = 2;
424  arr[1] = 3;
425  arr[2] = 5;
426  arr[3] = 7;
427  arr[4] = 11;
428  arr[5] = 13;
429  arr[6] = 17;
430  EXPECT_TRUE(a.generateRequest("DoFoo", arr));
431  EXPECT_EQ(header + "Content-length: 382\r\n\r\n"
432  "<?xml version=\"1.0\"?>\r\n"
433  "<methodCall><methodName>DoFoo</methodName>\r\n"
434  "<params>"
435  "<param><value><i4>2</i4></value></param>"
436  "<param><value><i4>3</i4></value></param>"
437  "<param><value><i4>5</i4></value></param>"
438  "<param><value><i4>7</i4></value></param>"
439  "<param><value><i4>11</i4></value></param>"
440  "<param><value><i4>13</i4></value></param>"
441  "<param><value><i4>17</i4></value></param>"
442  "</params></methodCall>\r\n",
443  a._request);
444 
445  // Tests for errors in arguments.
446  // Method name null
447  // TODO(austin): this causes a segfault.
448  /*
449  EXPECT_TRUE(a.generateRequest(NULL, s));
450  EXPECT_EQ(header + "Content-length: 134\r\n\r\n" \
451  "<?xml version=\"1.0\"?>\r\n" \
452  "<methodCall><methodName></methodName>\r\n" \
453  "<params><param><value>Hello</value></param></params></methodCall>\r\n"
454  , a._request);
455  */
456 
457  // Empty(invalid) param(s)
458  // NOTE(austin): this matches the existing implementation but seems unusual.
459  // I don't have a specification to check this against so I'm just going to
460  // assume it's OK.
461  XmlRpcValue empty;
462  EXPECT_FALSE(empty.valid());
463  EXPECT_TRUE(a.generateRequest("DoEmpty", empty));
464  EXPECT_EQ(header + "Content-length: 84\r\n\r\n"
465  "<?xml version=\"1.0\"?>\r\n"
466  "<methodCall><methodName>DoEmpty</methodName>\r\n"
467  "</methodCall>\r\n",
468  a._request);
469 }
470 
471 // Test generateHeader()
472 // Correct header is generated for various sizes and content of request body.
473 TEST(XmlRpcClient, generateHeader) {
474  XmlRpcClient a("localhost", 42);
475  // generateRequest takes a method name and params and puts the result in the
476  // _request member variable.
477  std::string header = "POST /RPC2 HTTP/1.1\r\n"
478  "User-Agent: XMLRPC++ 0.7\r\n"
479  "Host: localhost:42\r\n"
480  "Content-Type: text/xml\r\n";
481 
482  // Nonzero length message body.
483  EXPECT_EQ(header + "Content-length: 30\r\n\r\n", a.generateHeader(30));
484 
485  // Zero-length body as degenerate case.
486  EXPECT_EQ(header + "Content-length: 0\r\n\r\n", a.generateHeader(0));
487 }
488 
489 // Test writeRequest()
490 // Test that everything in a single write works; Client is left in the correct
491 // state.
492 // Test that partial write works, client is left in the correct state.
493 // Test that socket errors result in the correct state and that the socket
494 // is closed (or not) correctly.
495 TEST_F(MockSocketTest, writeRequest) {
496  XmlRpcClient a("localhost", 42);
497 
498  // Hack us into the correct initial state.
499  a.setfd(7);
501  a._request = "FAKE_REQUEST";
502 
503  // Check that request length is the correct size.
504  ASSERT_EQ(12u, a._request.size());
505 
506  // Expect a write; write all bytes and return success.
507  Expect_nbWrite(7, "FAKE_REQUEST", 12, true);
508 
509  // Expect that writeRequest is successful.
510  EXPECT_TRUE(a.writeRequest());
511 
512  // Check that resulting state is READ_HEADER
514 
515  // Check that all expected function calls were made before destruction.
516  CheckCalls();
517 
518  // Expect a close on destruction.
519  Expect_close(7);
520 }
521 
522 TEST_F(MockSocketTest, writeRequest_partial) {
523  XmlRpcClient a("localhost", 42);
524 
525  // Hack us into the correct initial state.
526  a.setfd(7);
528  a._request = "FAKE_REQUEST";
529 
530  // Check that request length is the correct size.
531  ASSERT_EQ(12u, a._request.size());
532 
533  // Expect a write; only write 5 bytes and return success.
534  Expect_nbWrite(7, "FAKE_REQUEST", 5, true);
535  // Expect that writeRequest is successful.
536  EXPECT_TRUE(a.writeRequest());
537  // Check that resulting state is READ_HEADER
539  // Check that all expected function calls were made.
540  CheckCalls();
541 
542  // Expect a write; write remaining bytes and return success.
543  Expect_nbWrite(7, "REQUEST", 7, true);
544  // Expect that writeRequest is successful.
545  EXPECT_TRUE(a.writeRequest());
546  // Check that resulting state is READ_HEADER
548  // Check that all expected function calls were made before destruction.
549  CheckCalls();
550 
551  // Expect a close on destruction.
552  Expect_close(7);
553 }
554 
555 TEST_F(MockSocketTest, writeRequest_partial_error) {
556  XmlRpcClient a("localhost", 42);
557 
558  // Hack us into the correct initial state.
559  a.setfd(7);
561  a._request = "FAKE_REQUEST";
562 
563  // Check that request length is the correct size.
564  ASSERT_EQ(12u, a._request.size());
565 
566  // Expect a write; only write 5 bytes and return success.
567  Expect_nbWrite(7, "FAKE_REQUEST", 5, true);
568  // Expect that writeRequest is successful.
569  EXPECT_TRUE(a.writeRequest());
570  // Check that resulting state is READ_HEADER
572  // Check that all expected function calls were made.
573  CheckCalls();
574 
575  // Expect a write; write no bytes and return failure.
576  Expect_nbWrite(7, "REQUEST", 0, false);
577  // Expect close, since the write failed.
578  Expect_close(7);
579  Expect_getError(ECONNREFUSED);
580  // Expect that writeRequest fails.
581  EXPECT_FALSE(a.writeRequest());
582  // Check that resulting state is not connected.
584 
585  // Check that all expected function calls were made before destruction.
586  CheckCalls();
587 }
588 
589 TEST_F(MockSocketTest, writeRequest_error) {
590  XmlRpcClient a("localhost", 42);
591 
592  // Hack us into the correct initial state.
593  a.setfd(7);
595  a._request = "FAKE_REQUEST";
596 
597  // Check that request length is the correct size.
598  ASSERT_EQ(12u, a._request.size());
599 
600  // Expect a write; write no bytes and return error.
601  Expect_nbWrite(7, "FAKE_REQUEST", 0, false);
602  Expect_close(7);
603  Expect_getError(ECONNREFUSED);
604  // Expect that writeRequest fails.
605  EXPECT_FALSE(a.writeRequest());
606  // Check that resulting state is not connected.
608 
609  // Check that all expected function calls were made before destruction.
610  CheckCalls();
611 }
612 
613 // Header as it would be generated by XmlRpcpp and body.
614 const std::string header = "HTTP/1.1 200 OK\r\n"
615  "Server: XMLRPC++ 0.7\r\n"
616  "Content-Type: text/xml\r\n"
617  "Content-length: 114\r\n\r\n";
618 // Alternate header as returned by roscore
619 const std::string header2 = "HTTP/1.0 200 OK\r\n"
620  "Server: BaseHTTP/0.3 Python/2.7.6\r\n"
621  "Date: Mon, 30 Oct 2017 22:28:12 GMT\r\n"
622  "Content-type: text/xml\r\n"
623  "Content-length: 114\r\n\r\n";
624 // Generic response XML
625 const std::string response = "<?xml version=\"1.0\"?>\r\n"
626  "<methodResponse><params><param>\r\n"
627  "<value>Hello</value>\r\n"
628  "</param></params></methodResponse>\r\n";
629 
630 // Test readHeader()
631 // Test that a full read with just a header works correctly.
632 // Test that various partial reads of the header work.
633 // Test that stacked partial reads of the header eventually result in success.
634 // Test that a read that returns both header and response data correctly
635 // removes the header and leaves the response.
636 // TODO(future work): Test the header parser in readHeader.
637 // TODO(future work): Test cases where the Content-length header is absent,
638 // zero, negative or garbage.
639 //
640 // Test that readHeader works correctly with the header from XmlRpcpp
641 TEST_F(MockSocketTest, readHeader) {
642  XmlRpcClient a("localhost", 42);
643 
644  // Hack us into the correct initial state.
645  a.setfd(7);
647 
648  // Self-test that response length matches encoded values above.
649  ASSERT_EQ(114u, response.length());
650 
651  // Expect a read and have it return the header and the response.
652  Expect_nbRead(7, header + response, false, true);
653 
654  EXPECT_TRUE(a.readHeader());
655 
656  // Check that state machine is in the correct state after getting the header.
658  // Check that the remaining response is stored in _response
659  EXPECT_EQ(response, a._response);
660  EXPECT_EQ(114, a._contentLength); // Check decoded content length
661 
662  // Check that all expected function calls were made before destruction.
663  CheckCalls();
664 
665  // Expect close on destruction.
666  Expect_close(7);
667 }
668 
669 // Test that readHeader works correctly with the header from roscore.
670 TEST_F(MockSocketTest, readHeader2) {
671  XmlRpcClient a("localhost", 42);
672 
673  // Hack us into the correct initial state.
674  a.setfd(7);
676 
677  // Expect a read and have it return the header and the response.
678  Expect_nbRead(7, header2 + response, false, true);
679 
680  EXPECT_TRUE(a.readHeader());
681 
682  // Check that state machine is in the correct state after getting the header.
684  // Check that the remaining response is stored in _response
685  EXPECT_EQ(response, a._response);
686  EXPECT_EQ(114, a._contentLength); // Check decoded content length
687 
688  // Check that all expected function calls were made before destruction.
689  CheckCalls();
690 
691  // Expect close on destruction.
692  Expect_close(7);
693 }
694 
695 // Test that readHeader decodes the content-length when read only returns the
696 // header.
697 // TODO(future work): there appears to be a bug in the header parsing where it
698 // doesn't pass the header parsing state until it gets the first byte of the
699 // response body.
700 TEST_F(MockSocketTest, readHeader_only) {
701  XmlRpcClient a("localhost", 42);
702 
703  // Hack us into the correct initial state.
704  a.setfd(7);
706 
707  // Expect a read and have it return only the header.
708  // NOTE(austin): the header parser doesn't terminate until it gets the first
709  // byte of the response; so give it one additional byte.
710  Expect_nbRead(7, header + " ", false, true);
711 
712  EXPECT_TRUE(a.readHeader());
713 
714  // Check that state machine is in the correct state after getting the header.
716  // Check that the remaining response is stored in _response
717  EXPECT_EQ(" ", a._response);
718  EXPECT_EQ(114, a._contentLength); // Check decoded content length
719 
720  // Check that all expected function calls were made before destruction.
721  CheckCalls();
722 
723  // Expect close on destruction.
724  Expect_close(7);
725 }
726 
727 // Test that readHeader correctly resumes after getting a partial header read.
728 TEST_F(MockSocketTest, readHeader_partial) {
729  XmlRpcClient a("localhost", 42);
730 
731  // Hack us into the correct initial state.
732  a.setfd(7);
734 
735  std::string header_part1 = header.substr(0, 32);
736  std::string header_part2 = header.substr(32);
737 
738  // Expect a read and have it return only part of the header.
739  Expect_nbRead(7, header_part1, false, true);
740  EXPECT_TRUE(a.readHeader());
741  // Check that state machine is in the correct state after getting the header.
743  // Check that the partial header is stored in _header.
744  EXPECT_EQ(header_part1, a._header);
745 
746  // Check that all expected function calls were made before we proceed.
747  CheckCalls();
748 
749  // Expect a read and have it return the remainder of the header.
750  Expect_nbRead(7, header_part2 + " ", false, true);
751  EXPECT_TRUE(a.readHeader());
752  // Check that state machine is in the correct state after getting the header.
754  // Check that the remaining response is stored in _response
755  EXPECT_EQ(" ", a._response);
756  EXPECT_EQ(114, a._contentLength); // Check decoded content length
757 
758  // Check that all expected function calls were made before destruction.
759  CheckCalls();
760 
761  // Expect close on destruction.
762  Expect_close(7);
763 }
764 
765 // Test that readHeader reports an error if the read fails.
766 TEST_F(MockSocketTest, readHeader_err) {
767  XmlRpcClient a("localhost", 42);
768 
769  // Hack us into the correct initial state.
770  a.setfd(7);
772 
773  // Expect a read and have it fail.
774  Expect_nbRead(7, "", false, false);
775  // Expect the client to close the socket.
776  Expect_close(7);
777  // Expect a reconnect attempt
778  Expect_socket(8);
779  Expect_setNonBlocking(8, true);
780  Expect_connect(8, "localhost", 42, true);
781 
782  EXPECT_TRUE(a.readHeader());
783 
784  // Check that state machine is in the correct state after getting the header.
786  EXPECT_EQ(1, a._sendAttempts);
787 
788  // Check that all expected function calls were made before destruction.
789  CheckCalls();
790 
791  // Skip the state machine forward to READ_HEADER state again.
793 
794  // Do it again, but this time don't expect a reconnect attempt
795  // Expect a read and have it return eof and success.
796  Expect_nbRead(8, "", true, true);
797  Expect_getError(ENOTCONN);
798  // Expect the client to close the socket.
799  Expect_close(8);
800 
801  EXPECT_FALSE(a.readHeader());
802 
803  // Check that state machine is in the correct state after getting the header.
805 
806  // Check that all expected function calls were made before destruction.
807  CheckCalls();
808 }
809 
810 // Test that readHeader reports an error if it gets EOF before it gets the
811 // content length.
812 TEST_F(MockSocketTest, readHeader_eof) {
813  XmlRpcClient a("localhost", 42);
814 
815  // Hack us into the correct initial state.
816  a.setfd(7);
818 
819  // Expect a read and have it return eof and success.
820  Expect_nbRead(7, "", true, true);
821  // Expect the client to close the socket.
822  Expect_close(7);
823  // Expect a reconnect attempt
824  Expect_socket(8);
825  Expect_setNonBlocking(8, true);
826  Expect_connect(8, "localhost", 42, true);
827 
828  EXPECT_TRUE(a.readHeader());
829 
830  // Check that state machine is in the correct state after getting the header.
832  EXPECT_EQ(1, a._sendAttempts);
833 
834  // Check that all expected function calls were made before destruction.
835  CheckCalls();
836 
837  // Skip the state machine forward to READ_HEADER state again.
839 
840  // Do it again, but this time don't expect a reconnect attempt
841  // Expect a read and have it return eof and success.
842  Expect_nbRead(8, "", true, true);
843  Expect_getError(ENOTCONN);
844  // Expect the client to close the socket.
845  Expect_close(8);
846 
847  EXPECT_FALSE(a.readHeader());
848 
849  // Check that state machine is in the correct state after getting the header.
851 
852  // Check that all expected function calls were made before destruction.
853  CheckCalls();
854 }
855 
856 // Test that readHeader reports an error and closes the socket if the second
857 // part of a partial read returns an error.
858 TEST_F(MockSocketTest, readHeader_partial_err) {
859  XmlRpcClient a("localhost", 42);
860 
861  // Hack us into the correct initial state.
862  a.setfd(7);
864 
865  std::string header_part1 = header.substr(0, 32);
866 
867  // Expect a read and have it return only part of the header.
868  Expect_nbRead(7, header_part1, false, true);
869  EXPECT_TRUE(a.readHeader());
870  // Check that state machine is in the correct state after getting the header.
872  // Check that the partial header is stored in _header.
873  EXPECT_EQ(header_part1, a._header);
874 
875  // Check that all expected function calls were made before we proceed.
876  CheckCalls();
877 
878  // Expect a read and have it return an error.
879  Expect_nbRead(7, "", false, false);
880  Expect_close(7);
881  // Expect a reconnect attempt
882  Expect_socket(8);
883  Expect_setNonBlocking(8, true);
884  Expect_connect(8, "localhost", 42, true);
885 
886  EXPECT_TRUE(a.readHeader());
887  // Check that state machine is in the correct state after getting the header.
889 
890  // Check that all expected function calls were made before destruction.
891  CheckCalls();
892 
893  // Expect socket close on destruction.
894  Expect_close(8);
895 }
896 
897 // Test readResponse()
898 // Test read of response in a single read call
899 // Test response spread across several read calls
900 // Test empty response
901 // Test read errors on first or subsequent reads
902 // Test for correct state after each of these events.
903 
904 // Test that readResponse does nothing if _response is already populated by
905 // readHeader.
906 TEST_F(MockSocketTest, readResponse_noop) {
907  XmlRpcClient a("localhost", 42);
908 
909  // Hack us into the correct initial state.
910  a.setfd(7);
912  // Response was already read by readHeader
913  // (verified by previous tests).
914  a._response = response;
915  a._contentLength = 114;
916  ASSERT_EQ(114u, a._response.length());
917 
918  // Don't expect any calls. Expect readResponse to return false since we don't
919  // need to keep monitoring this client.
920  EXPECT_FALSE(a.readResponse());
921 
922  // Check that state machine is in the correct state after getting the header.
923  EXPECT_EQ(XmlRpcClient::IDLE, a._connectionState);
924  // Check that the remaining response is stored in _response
925  EXPECT_EQ(response, a._response);
926  EXPECT_EQ(114, a._contentLength); // Check decoded content length
927 
928  // Check that all expected function calls were made before destruction.
929  CheckCalls();
930 
931  // Expect close on destruction.
932  Expect_close(7);
933 }
934 
935 // Test that readResponse works if the initial buffer is empty.
936 TEST_F(MockSocketTest, readResponse) {
937  XmlRpcClient a("localhost", 42);
938 
939  // Hack us into the correct initial state.
940  a.setfd(7);
942  // Start with empty response and pre-populated content length.
943  a._response = "";
944  a._contentLength = 114;
945  ASSERT_EQ(114u, response.length());
946 
947  // Expect a read, have it return the full response and success.
948  Expect_nbRead(7, response, false, true);
949  // Expect readResponse to return false since we're done monitoring this
950  // socket.
951  EXPECT_FALSE(a.readResponse());
952 
953  // Check that state machine is in the correct state after getting the header.
954  EXPECT_EQ(XmlRpcClient::IDLE, a._connectionState);
955  // Check that the remaining response is stored in _response
956  EXPECT_EQ(response, a._response);
957 
958  // Check that all expected function calls were made before destruction.
959  CheckCalls();
960 
961  // Expect close on destruction.
962  Expect_close(7);
963 }
964 
965 // Test that readResponse works if the initial buffer is empty.
966 TEST_F(MockSocketTest, readResponse_partial) {
967  XmlRpcClient a("localhost", 42);
968 
969  // Hack us into the correct initial state.
970  a.setfd(7);
972  // Start with empty response and pre-populated content length.
973  a._response = "";
974  a._contentLength = 114;
975  ASSERT_EQ(114u, response.length());
976 
977  const std::string response_part1 = response.substr(0, 60);
978  const std::string response_part2 = response.substr(60);
979 
980  // Expect a read, have it return the first part of the response.
981  Expect_nbRead(7, response_part1, false, true);
982  EXPECT_TRUE(a.readResponse());
983 
984  // Check that the first part of the response is stored in _response
985  EXPECT_EQ(response_part1, a._response);
986  // Check that state machine is in the correct state after getting the header.
988 
989  // Check that all expected function calls were made before destruction.
990  CheckCalls();
991 
992  // Expect a read, have it return the remainder of the response and success.
993  Expect_nbRead(7, response_part2, false, true);
994 
995  // Expect readResponse to return false now since we're done monitoring this
996  // socket.
997  EXPECT_FALSE(a.readResponse());
998 
999  // Check that state machine is in the correct state after getting the header.
1000  EXPECT_EQ(XmlRpcClient::IDLE, a._connectionState);
1001  // Check that the remaining response is stored in _response
1002  EXPECT_EQ(response, a._response);
1003 
1004  // Check that all expected function calls were made before destruction.
1005  CheckCalls();
1006 
1007  // Expect close on destruction.
1008  Expect_close(7);
1009 }
1010 
1011 // Test that readResponse closes the socket and returns an error if the read
1012 // fails.
1013 TEST_F(MockSocketTest, readResponse_err) {
1014  XmlRpcClient a("localhost", 42);
1015 
1016  // Hack us into the correct initial state.
1017  a.setfd(7);
1019  // Start with empty response and pre-populated content length.
1020  a._response = "";
1021  a._contentLength = 114;
1022  ASSERT_EQ(114u, response.length());
1023 
1024  // Expect a read, have it return an error.
1025  Expect_nbRead(7, "", false, false);
1026  // Expect getError and close()
1027  Expect_getError(ENOTCONN);
1028  Expect_close(7);
1029  // Expect readResponse to return false since we're done monitoring this
1030  // socket.
1031  EXPECT_FALSE(a.readResponse());
1032 
1033  // Check that state machine is in the correct state after getting the header.
1035 
1036  // Check that all expected function calls were made before destruction.
1037  CheckCalls();
1038 }
1039 
1040 // Test that readResponse works if the initial buffer is empty.
1041 TEST_F(MockSocketTest, readResponse_eof) {
1042  XmlRpcClient a("localhost", 42);
1043 
1044  // Hack us into the correct initial state.
1045  a.setfd(7);
1047  // Start with empty response and pre-populated content length.
1048  a._response = "";
1049  a._contentLength = 114;
1050  ASSERT_EQ(114u, response.length());
1051 
1052  // Expect a read, have it return nothing and EOF.
1053  Expect_nbRead(7, "", true, true);
1054  // Expect that we close the socket.
1055  Expect_close(7);
1056  // Expect readResponse to return false since we're done monitoring this
1057  // socket.
1058  EXPECT_FALSE(a.readResponse());
1059 
1060  // Check that state machine is in the correct state after getting the header.
1062 
1063  // Check that all expected function calls were made before destruction.
1064  CheckCalls();
1065 }
1066 
1067 // Test parseResponse
1068 // Test correct parsing of various response types: empty, int, double,
1069 // string, bool, list, struct, date, base64, etc
1070 // Test for correct handling of empty response body
1071 // Test for correct parsing/handling of partial response
1072 // Test for correct handling of garbage data
1073 // Test for correct handling of mismatched XML tags at top level
1074 // Test for correct handling of ALL UPPERCASE, lowercase and CamelCase tags
1075 
1076 int main(int argc, char **argv)
1077 {
1078  ::testing::InitGoogleTest(&argc, argv);
1079  return RUN_ALL_TESTS();
1080 }
virtual bool generateRequest(const char *method, XmlRpcValue const &params)
bool getKeepOpen() const
Return whether the file descriptor should be kept open if it is no longer monitored.
Definition: XmlRpcSource.h:32
void PrintTo(const XmlRpcClient::ClientConnectionState &state,::std::ostream *os)
Definition: test_client.cpp:38
RPC method arguments and results are represented by Values.
Definition: XmlRpcValue.h:24
virtual bool readHeader()
XmlRpcServer s
Definition: HelloServer.cpp:11
bool valid() const
Return true if the value has been set to something.
Definition: XmlRpcValue.h:108
std::string _request
Definition: XmlRpcClient.h:105
TEST(xmlrpcvalue_base64, empty_string)
int main(int argc, char **argv)
virtual void close()
Close the connection.
XmlRpcDispatch _disp
Definition: XmlRpcClient.h:131
int getfd() const
Return the file descriptor being monitored.
Definition: XmlRpcSource.h:27
ClientConnectionState _connectionState
Definition: XmlRpcClient.h:91
TEST_F(MockSocketTest, constructor)
Definition: test_client.cpp:71
void setfd(int fd)
Specify the file descriptor to monitor.
Definition: XmlRpcSource.h:29
bool sourceInList(XmlRpc::XmlRpcSource *source, const XmlRpc::XmlRpcDispatch::SourceList &list)
Definition: test_client.cpp:45
An RPC source represents a file descriptor to monitor.
Definition: XmlRpcSource.h:16
static const char * connectionStateStr(ClientConnectionState state)
virtual bool doConnect()
const std::string header2
virtual std::string generateHeader(size_t length) const
A class to send XML RPC requests to a server and return the results.
Definition: XmlRpcClient.h:26
std::string _response
Definition: XmlRpcClient.h:107
const std::string header
std::list< MonitoredSource > SourceList
#define TEST_STATE(state)
virtual bool setupConnection()
virtual bool readResponse()
const std::string response
virtual bool writeRequest()


xmlrpcpp
Author(s): Chris Morley, Konstantin Pilipchuk, Morgan Quigley, Austin Hendrix
autogenerated on Sun Feb 3 2019 03:29:51