]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | /* |
2 | * Licensed to the Apache Software Foundation (ASF) under one | |
3 | * or more contributor license agreements. See the NOTICE file | |
4 | * distributed with this work for additional information | |
5 | * regarding copyright ownership. The ASF licenses this file | |
6 | * to you under the Apache License, Version 2.0 (the | |
7 | * "License"); you may not use this file except in compliance | |
8 | * with the License. You may obtain a copy of the License at | |
9 | * | |
10 | * http://www.apache.org/licenses/LICENSE-2.0 | |
11 | * | |
12 | * Unless required by applicable law or agreed to in writing, | |
13 | * software distributed under the License is distributed on an | |
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
15 | * KIND, either express or implied. See the License for the | |
16 | * specific language governing permissions and limitations | |
17 | * under the License. | |
18 | */ | |
19 | ||
20 | #include <limits> | |
21 | #include <locale> | |
22 | #include <ios> | |
23 | #include <iostream> | |
24 | #include <sstream> | |
25 | #include <thrift/protocol/TBinaryProtocol.h> | |
26 | #include <thrift/protocol/TCompactProtocol.h> | |
27 | #include <thrift/protocol/THeaderProtocol.h> | |
28 | #include <thrift/protocol/TJSONProtocol.h> | |
29 | #include <thrift/protocol/TMultiplexedProtocol.h> | |
30 | #include <thrift/transport/THttpClient.h> | |
31 | #include <thrift/transport/TTransportUtils.h> | |
32 | #include <thrift/transport/TSocket.h> | |
33 | #include <thrift/transport/TSSLSocket.h> | |
34 | #include <thrift/transport/TZlibTransport.h> | |
35 | #include <thrift/async/TEvhttpClientChannel.h> | |
36 | #include <thrift/server/TNonblockingServer.h> // <event.h> | |
37 | ||
38 | #ifdef HAVE_STDINT_H | |
39 | #include <stdint.h> | |
40 | #endif | |
41 | #ifdef HAVE_INTTYPES_H | |
42 | #include <inttypes.h> | |
43 | #endif | |
44 | ||
45 | #include <boost/algorithm/string.hpp> | |
46 | #include <boost/filesystem.hpp> | |
47 | #include <boost/program_options.hpp> | |
48 | #include <boost/random/random_device.hpp> | |
49 | #if _WIN32 | |
50 | #include <thrift/windows/TWinsockSingleton.h> | |
51 | #endif | |
52 | ||
53 | #include "SecondService.h" | |
54 | #include "ThriftTest.h" | |
55 | ||
56 | using namespace std; | |
57 | using namespace apache::thrift; | |
58 | using namespace apache::thrift::async; | |
59 | using namespace apache::thrift::protocol; | |
60 | using namespace apache::thrift::transport; | |
61 | using namespace thrift::test; | |
62 | ||
63 | // | |
64 | // A pedantic protocol that checks to make sure the response sequence ID | |
65 | // is the same as the sent sequence ID. lib/cpp always sends zero for | |
66 | // synchronous clients, so this bumps the number to make sure it gets | |
67 | // returned properly from the remote server. Any server that does not | |
68 | // respond with the same sequence number is violating the sequence ID | |
69 | // agreement between client and server. | |
70 | // | |
71 | ||
72 | template<typename Proto> | |
73 | class TPedanticProtocol : public Proto | |
74 | { | |
75 | public: | |
76 | TPedanticProtocol(std::shared_ptr<TTransport>& transport) | |
77 | : Proto(transport), m_last_seqid((std::numeric_limits<int32_t>::max)() - 10) { } | |
78 | ||
79 | virtual uint32_t writeMessageBegin_virt(const std::string& name, | |
80 | const TMessageType messageType, | |
81 | const int32_t in_seqid) override | |
82 | { | |
83 | int32_t seqid = in_seqid; | |
84 | if (!seqid) { // this is typical for normal cpp generated code | |
85 | seqid = ++m_last_seqid; | |
86 | } | |
87 | ||
88 | return Proto::writeMessageBegin_virt(name, messageType, seqid); | |
89 | } | |
90 | ||
91 | virtual uint32_t readMessageBegin_virt(std::string& name, | |
92 | TMessageType& messageType, | |
93 | int32_t& seqid) override | |
94 | { | |
95 | uint32_t result = Proto::readMessageBegin_virt(name, messageType, seqid); | |
96 | if (seqid != m_last_seqid) { | |
97 | std::stringstream ss; | |
98 | ss << "ERROR: send request with seqid " << m_last_seqid << " and got reply with seqid " << seqid; | |
99 | throw std::logic_error(ss.str()); | |
100 | } /* else { | |
101 | std::cout << "verified seqid " << m_last_seqid << " round trip OK" << std::endl; | |
102 | } */ | |
103 | return result; | |
104 | } | |
105 | ||
106 | private: | |
107 | int32_t m_last_seqid; | |
108 | }; | |
109 | ||
110 | // Current time, microseconds since the epoch | |
111 | uint64_t now() { | |
112 | int64_t ret; | |
113 | struct timeval tv; | |
114 | ||
115 | THRIFT_GETTIMEOFDAY(&tv, nullptr); | |
116 | ret = tv.tv_sec; | |
117 | ret = ret * 1000 * 1000 + tv.tv_usec; | |
118 | return ret; | |
119 | } | |
120 | ||
121 | static void testString_clientReturn(event_base* base, | |
122 | int testNr, | |
123 | ThriftTestCobClient* client) { | |
124 | try { | |
125 | string s; | |
126 | client->recv_testString(s); | |
127 | std::ostringstream os; | |
128 | os << "test" << testNr; | |
129 | const bool ok = (s == os.str()); | |
130 | cout << "testString: " << s << " " << ((ok) ? "ok" : "failed") << endl; | |
131 | } catch (TException& exn) { | |
132 | cout << "Error: " << exn.what() << endl; | |
133 | } | |
134 | ||
135 | if (testNr == 9) | |
136 | event_base_loopbreak(base); // end test | |
137 | } | |
138 | ||
139 | static void testVoid_clientReturn(event_base* base, ThriftTestCobClient* client) { | |
140 | try { | |
141 | client->recv_testVoid(); | |
142 | cout << "testVoid" << endl; | |
143 | ||
144 | for (int testNr = 0; testNr < 10; ++testNr) { | |
145 | std::ostringstream os; | |
146 | os << "test" << testNr; | |
147 | client->testString(std::bind(testString_clientReturn, | |
148 | base, | |
149 | testNr, | |
150 | std::placeholders::_1), | |
151 | os.str()); | |
152 | } | |
153 | } catch (TException& exn) { | |
154 | cout << "Error: " << exn.what() << endl; | |
155 | } | |
156 | } | |
157 | ||
158 | // Workaround for absense of C++11 "auto" keyword. | |
159 | template <typename T> | |
160 | bool print_eq(T expected, T actual) { | |
161 | cout << "(" << actual << ")" << endl; | |
162 | if (expected != actual) { | |
163 | cout << "*** FAILED ***" << endl << "Expected: " << expected << " but got: " << actual << endl; | |
164 | return false; | |
165 | } | |
166 | return true; | |
167 | } | |
168 | ||
169 | #define BASETYPE_IDENTITY_TEST(func, value) \ | |
170 | cout << #func "(" << value << ") = "; \ | |
171 | try { \ | |
172 | if (!print_eq(value, testClient.func(value))) \ | |
173 | return_code |= ERR_BASETYPES; \ | |
174 | } catch (TTransportException&) { \ | |
175 | throw; \ | |
176 | } catch (exception & ex) { \ | |
177 | cout << "*** FAILED ***" << endl << ex.what() << endl; \ | |
178 | return_code |= ERR_BASETYPES; \ | |
179 | } | |
180 | ||
181 | int binary_test(ThriftTestClient& testClient, string::size_type siz); | |
182 | ||
183 | BOOST_CONSTEXPR_OR_CONST int ERR_BASETYPES = 1; | |
184 | BOOST_CONSTEXPR_OR_CONST int ERR_STRUCTS = 2; | |
185 | BOOST_CONSTEXPR_OR_CONST int ERR_CONTAINERS = 4; | |
186 | BOOST_CONSTEXPR_OR_CONST int ERR_EXCEPTIONS = 8; | |
187 | BOOST_CONSTEXPR_OR_CONST int ERR_UNKNOWN = 64; | |
188 | ||
189 | int main(int argc, char** argv) { | |
190 | cout.precision(19); | |
191 | ||
192 | string testDir = boost::filesystem::system_complete(argv[0]).parent_path().parent_path().parent_path().string(); | |
193 | string caPath = testDir + "/keys/CA.pem"; | |
194 | string certPath = testDir + "/keys/client.crt"; | |
195 | string keyPath = testDir + "/keys/client.key"; | |
196 | ||
197 | #if _WIN32 | |
198 | transport::TWinsockSingleton::create(); | |
199 | #endif | |
200 | string host = "localhost"; | |
201 | int port = 9090; | |
202 | int numTests = 1; | |
203 | bool ssl = false; | |
204 | bool zlib = false; | |
205 | string transport_type = "buffered"; | |
206 | string protocol_type = "binary"; | |
207 | string domain_socket = ""; | |
208 | bool abstract_namespace = false; | |
209 | bool noinsane = false; | |
210 | ||
211 | int return_code = 0; | |
212 | ||
213 | boost::program_options::options_description desc("Allowed options"); | |
214 | desc.add_options() | |
215 | ("help,h", "produce help message") | |
216 | ("host", | |
217 | boost::program_options::value<string>(&host)->default_value(host), | |
218 | "Host to connect") | |
219 | ("port", | |
220 | boost::program_options::value<int>(&port)->default_value(port), | |
221 | "Port number to connect") | |
222 | ("domain-socket", | |
223 | boost::program_options::value<string>(&domain_socket)->default_value(domain_socket), | |
224 | "Domain Socket (e.g. /tmp/ThriftTest.thrift), instead of host and port") | |
225 | ("abstract-namespace", | |
226 | "Look for the domain socket in the Abstract Namespace" | |
227 | " (no connection with filesystem pathnames)") | |
228 | ("transport", | |
229 | boost::program_options::value<string>(&transport_type)->default_value(transport_type), | |
230 | "Transport: buffered, framed, http, evhttp, zlib") | |
231 | ("protocol", | |
232 | boost::program_options::value<string>(&protocol_type)->default_value(protocol_type), | |
233 | "Protocol: binary, compact, header, json, multi, multic, multih, multij") | |
234 | ("ssl", | |
235 | "Encrypted Transport using SSL") | |
236 | ("zlib", | |
237 | "Wrap Transport with Zlib") | |
238 | ("testloops,n", | |
239 | boost::program_options::value<int>(&numTests)->default_value(numTests), | |
240 | "Number of Tests") | |
241 | ("noinsane", | |
242 | "Do not run insanity test"); | |
243 | ||
244 | boost::program_options::variables_map vm; | |
245 | boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm); | |
246 | boost::program_options::notify(vm); | |
247 | ||
248 | if (vm.count("help")) { | |
249 | cout << desc << endl; | |
250 | return ERR_UNKNOWN; | |
251 | } | |
252 | ||
253 | try { | |
254 | if (!protocol_type.empty()) { | |
255 | if (protocol_type == "binary") { | |
256 | } else if (protocol_type == "compact") { | |
257 | } else if (protocol_type == "header") { | |
258 | } else if (protocol_type == "json") { | |
259 | } else if (protocol_type == "multi") { | |
260 | } else if (protocol_type == "multic") { | |
261 | } else if (protocol_type == "multih") { | |
262 | } else if (protocol_type == "multij") { | |
263 | } else { | |
264 | throw invalid_argument("Unknown protocol type " + protocol_type); | |
265 | } | |
266 | } | |
267 | ||
268 | if (!transport_type.empty()) { | |
269 | if (transport_type == "buffered") { | |
270 | } else if (transport_type == "framed") { | |
271 | } else if (transport_type == "http") { | |
272 | } else if (transport_type == "evhttp") { | |
273 | } else if (transport_type == "zlib") { | |
274 | // crosstest will pass zlib as a transport and as a flag right now.. | |
275 | } else { | |
276 | throw invalid_argument("Unknown transport type " + transport_type); | |
277 | } | |
278 | } | |
279 | ||
280 | } catch (exception& e) { | |
281 | cerr << e.what() << endl; | |
282 | cout << desc << endl; | |
283 | return ERR_UNKNOWN; | |
284 | } | |
285 | ||
286 | if (vm.count("ssl")) { | |
287 | ssl = true; | |
288 | } | |
289 | ||
290 | if (vm.count("zlib")) { | |
291 | zlib = true; | |
292 | } | |
293 | ||
294 | if (vm.count("abstract-namespace")) { | |
295 | abstract_namespace = true; | |
296 | } | |
297 | ||
298 | if (vm.count("noinsane")) { | |
299 | noinsane = true; | |
300 | } | |
301 | ||
302 | // THRIFT-4164: The factory MUST outlive any sockets it creates for correct behavior! | |
303 | std::shared_ptr<TSSLSocketFactory> factory; | |
304 | std::shared_ptr<TSocket> socket; | |
305 | std::shared_ptr<TTransport> transport; | |
306 | std::shared_ptr<TProtocol> protocol; | |
307 | std::shared_ptr<TProtocol> protocol2; // SecondService for multiplexed | |
308 | ||
309 | if (ssl) { | |
310 | cout << "Client Certificate File: " << certPath << endl; | |
311 | cout << "Client Key File: " << keyPath << endl; | |
312 | cout << "CA File: " << caPath << endl; | |
313 | ||
314 | factory = std::shared_ptr<TSSLSocketFactory>(new TSSLSocketFactory()); | |
315 | factory->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); | |
316 | factory->loadTrustedCertificates(caPath.c_str()); | |
317 | factory->loadCertificate(certPath.c_str()); | |
318 | factory->loadPrivateKey(keyPath.c_str()); | |
319 | factory->authenticate(true); | |
320 | socket = factory->createSocket(host, port); | |
321 | } else { | |
322 | if (domain_socket != "") { | |
323 | if (abstract_namespace) { | |
324 | std::string abstract_socket("\0", 1); | |
325 | abstract_socket += domain_socket; | |
326 | socket = std::shared_ptr<TSocket>(new TSocket(abstract_socket)); | |
327 | } else { | |
328 | socket = std::shared_ptr<TSocket>(new TSocket(domain_socket)); | |
329 | } | |
330 | port = 0; | |
331 | } else { | |
332 | socket = std::shared_ptr<TSocket>(new TSocket(host, port)); | |
333 | } | |
334 | } | |
335 | ||
336 | if (transport_type.compare("http") == 0) { | |
337 | transport = std::make_shared<THttpClient>(socket, host, "/service"); | |
338 | } else if (transport_type.compare("framed") == 0) { | |
339 | transport = std::make_shared<TFramedTransport>(socket); | |
340 | } else { | |
341 | transport = std::make_shared<TBufferedTransport>(socket); | |
342 | } | |
343 | ||
344 | if (zlib) { | |
345 | transport = std::make_shared<TZlibTransport>(transport); | |
346 | } | |
347 | ||
348 | if (protocol_type == "json" || protocol_type == "multij") { | |
349 | typedef TPedanticProtocol<TJSONProtocol> TPedanticJSONProtocol; | |
350 | protocol = std::make_shared<TPedanticJSONProtocol>(transport); | |
351 | } else if (protocol_type == "compact" || protocol_type == "multic") { | |
352 | typedef TPedanticProtocol<TCompactProtocol> TPedanticCompactProtocol; | |
353 | protocol = std::make_shared<TPedanticCompactProtocol>(transport); | |
354 | } else if (protocol_type == "header" || protocol_type == "multih") { | |
355 | typedef TPedanticProtocol<THeaderProtocol> TPedanticHeaderProtocol; | |
356 | protocol = std::make_shared<TPedanticHeaderProtocol>(transport); | |
357 | } else { | |
358 | typedef TPedanticProtocol<TBinaryProtocol> TPedanticBinaryProtocol; | |
359 | protocol = std::make_shared<TPedanticBinaryProtocol>(transport); | |
360 | } | |
361 | ||
362 | if (boost::starts_with(protocol_type, "multi")) { | |
363 | protocol2 = std::make_shared<TMultiplexedProtocol>(protocol, "SecondService"); | |
364 | // we don't need access to the original protocol any more, so... | |
365 | protocol = std::make_shared<TMultiplexedProtocol>(protocol, "ThriftTest"); | |
366 | } | |
367 | ||
368 | // Connection info | |
369 | cout << "Connecting (" << transport_type << "/" << protocol_type << ") to: "; | |
370 | if (abstract_namespace) { | |
371 | cout << '@'; | |
372 | } | |
373 | cout << domain_socket; | |
374 | if (port != 0) { | |
375 | cout << host << ":" << port; | |
376 | } | |
377 | cout << endl; | |
378 | ||
379 | if (transport_type.compare("evhttp") == 0) { | |
380 | event_base* base = event_base_new(); | |
381 | cout << "Libevent Version: " << event_get_version() << endl; | |
382 | cout << "Libevent Method: " << event_base_get_method(base) << endl; | |
383 | #if LIBEVENT_VERSION_NUMBER >= 0x02000000 | |
384 | cout << "Libevent Features: 0x" << hex << event_base_get_features(base) << endl; | |
385 | #endif | |
386 | ||
387 | std::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory()); | |
388 | ||
389 | std::shared_ptr<TAsyncChannel> channel( | |
390 | new TEvhttpClientChannel(host.c_str(), "/", host.c_str(), port, base)); | |
391 | ThriftTestCobClient* client = new ThriftTestCobClient(channel, protocolFactory.get()); | |
392 | client->testVoid(std::bind(testVoid_clientReturn, | |
393 | base, | |
394 | std::placeholders::_1)); | |
395 | ||
396 | event_base_loop(base, 0); | |
397 | return 0; | |
398 | } | |
399 | ||
400 | ThriftTestClient testClient(protocol); | |
401 | ||
402 | uint64_t time_min = 0; | |
403 | uint64_t time_max = 0; | |
404 | uint64_t time_tot = 0; | |
405 | ||
406 | int test = 0; | |
407 | for (test = 0; test < numTests; ++test) { | |
408 | ||
409 | try { | |
410 | transport->open(); | |
411 | } catch (TTransportException& ex) { | |
412 | cout << "Connect failed: " << ex.what() << endl; | |
413 | return ERR_UNKNOWN; | |
414 | } | |
415 | ||
416 | /** | |
417 | * CONNECT TEST | |
418 | */ | |
419 | printf("Test #%d, connect %s:%d\n", test + 1, host.c_str(), port); | |
420 | ||
421 | uint64_t start = now(); | |
422 | ||
423 | /** | |
424 | * VOID TEST | |
425 | */ | |
426 | try { | |
427 | cout << "testVoid()" << flush; | |
428 | testClient.testVoid(); | |
429 | cout << " = void" << endl; | |
430 | } catch (TTransportException&) { | |
431 | // Stop here if transport got broken | |
432 | throw; | |
433 | } catch (exception& ex) { | |
434 | cout << "*** FAILED ***" << endl << ex.what() << endl; | |
435 | return_code |= ERR_BASETYPES; | |
436 | } | |
437 | ||
438 | /** | |
439 | * STRING TEST | |
440 | */ | |
441 | cout << "testString(\"Test\")" << flush; | |
442 | string s; | |
443 | testClient.testString(s, "Test"); | |
444 | cout << " = " << s << endl; | |
445 | if (s != "Test") { | |
446 | cout << "*** FAILED ***" << endl; | |
447 | return_code |= ERR_BASETYPES; | |
448 | } | |
449 | ||
450 | // | |
451 | // Multiplexed protocol - call another service method | |
452 | // in the middle of the ThriftTest | |
453 | // | |
454 | if (boost::starts_with(protocol_type, "multi")) { | |
455 | SecondServiceClient ssc(protocol2); | |
456 | // transport is already open... | |
457 | ||
458 | try { | |
459 | cout << "secondService.secondTestString(\"foo\") => " << flush; | |
460 | std::string result; | |
461 | ssc.secondtestString(result, "foo"); | |
462 | cout << "{" << result << "}" << endl; | |
463 | } catch (std::exception& e) { | |
464 | cout << " *** FAILED *** " << e.what() << endl; | |
465 | return_code |= ERR_EXCEPTIONS; | |
466 | } | |
467 | } | |
468 | ||
469 | try { | |
470 | #ifdef _MSC_VER | |
471 | #pragma warning( push ) | |
472 | #pragma warning( disable : 4566 ) | |
473 | #endif | |
474 | string str( | |
475 | "}{Afrikaans, Alemannisch, Aragonés, العربية, مصرى, " | |
476 | "Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, " | |
477 | "Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, " | |
478 | "বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, " | |
479 | "Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, " | |
480 | "Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, " | |
481 | "Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, " | |
482 | "Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, " | |
483 | "Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, " | |
484 | "Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, " | |
485 | "Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, " | |
486 | "ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, " | |
487 | "Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, " | |
488 | "Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa " | |
489 | "Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa " | |
490 | "Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, " | |
491 | "Norsk (nynorsk), Norsk (bokmål), Nouormand, Diné bizaad, " | |
492 | "Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو, " | |
493 | "Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română, " | |
494 | "Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple " | |
495 | "English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, " | |
496 | "Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, " | |
497 | "Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, " | |
498 | "Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, " | |
499 | "Bân-lâm-gú, 粵語"); | |
500 | #ifdef _MSC_VER | |
501 | #pragma warning( pop ) | |
502 | #endif | |
503 | cout << "testString(" << str << ") = " << flush; | |
504 | testClient.testString(s, str); | |
505 | cout << s << endl; | |
506 | if (s != str) { | |
507 | cout.imbue(locale("en_US.UTF8")); | |
508 | cout << "*** FAILED ***" << endl << "Expected string: " << str << " but got: " << s << endl << "CLEAR"; | |
509 | return_code |= ERR_BASETYPES; | |
510 | } | |
511 | } catch (TTransportException&) { | |
512 | throw; | |
513 | } catch (exception& ex) { | |
514 | cout << "*** FAILED ***" << endl << ex.what() << endl; | |
515 | return_code |= ERR_BASETYPES; | |
516 | return return_code; | |
517 | } | |
518 | try { | |
519 | string str( | |
520 | "quote: \" backslash:" | |
521 | " forwardslash-escaped: \\/ " | |
522 | " backspace: \b formfeed: \f newline: \n return: \r tab: " | |
523 | " now-all-of-them-together: \"\\\\/\b\n\r\t" | |
524 | " now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><" | |
525 | " char-to-test-json-parsing: ]] \"]] \\\" }}}{ [[[ "); | |
526 | cout << "testString(" << str << ") = " << flush; | |
527 | testClient.testString(s, str); | |
528 | cout << s << endl; | |
529 | if (s != str) { | |
530 | cout.imbue(locale("en_US.UTF8")); | |
531 | cout << "*** FAILED ***" << endl | |
532 | << "Expected string: " << str << " but got: " << s << endl | |
533 | << "CLEAR"; | |
534 | ; | |
535 | return_code |= ERR_BASETYPES; | |
536 | } | |
537 | } catch (TTransportException&) { | |
538 | throw; | |
539 | } catch (exception& ex) { | |
540 | cout << "*** FAILED ***" << endl << ex.what() << endl; | |
541 | return_code |= ERR_BASETYPES; | |
542 | return return_code; | |
543 | } | |
544 | ||
545 | /** | |
546 | * BOOL TEST | |
547 | */ | |
548 | cout << boolalpha; | |
549 | BASETYPE_IDENTITY_TEST(testBool, true); | |
550 | BASETYPE_IDENTITY_TEST(testBool, false); | |
551 | ||
552 | /** | |
553 | * BYTE TEST | |
554 | */ | |
555 | BASETYPE_IDENTITY_TEST(testByte, (int8_t)0); | |
556 | BASETYPE_IDENTITY_TEST(testByte, (int8_t)-1); | |
557 | BASETYPE_IDENTITY_TEST(testByte, (int8_t)42); | |
558 | BASETYPE_IDENTITY_TEST(testByte, (int8_t)-42); | |
559 | BASETYPE_IDENTITY_TEST(testByte, (int8_t)127); | |
560 | BASETYPE_IDENTITY_TEST(testByte, (int8_t)-128); | |
561 | ||
562 | /** | |
563 | * I32 TEST | |
564 | */ | |
565 | BASETYPE_IDENTITY_TEST(testI32, 0); | |
566 | BASETYPE_IDENTITY_TEST(testI32, -1); | |
567 | BASETYPE_IDENTITY_TEST(testI32, 190000013); | |
568 | BASETYPE_IDENTITY_TEST(testI32, -190000013); | |
569 | BASETYPE_IDENTITY_TEST(testI32, (numeric_limits<int32_t>::max)()); | |
570 | BASETYPE_IDENTITY_TEST(testI32, (numeric_limits<int32_t>::min)()); | |
571 | ||
572 | /** | |
573 | * I64 TEST | |
574 | */ | |
575 | BASETYPE_IDENTITY_TEST(testI64, (int64_t)0); | |
576 | BASETYPE_IDENTITY_TEST(testI64, (int64_t)-1); | |
577 | BASETYPE_IDENTITY_TEST(testI64, (int64_t)7000000000000000123LL); | |
578 | BASETYPE_IDENTITY_TEST(testI64, (int64_t)-7000000000000000123LL); | |
579 | BASETYPE_IDENTITY_TEST(testI64, (int64_t)pow(static_cast<double>(2LL), 32)); | |
580 | BASETYPE_IDENTITY_TEST(testI64, (int64_t)-pow(static_cast<double>(2LL), 32)); | |
581 | BASETYPE_IDENTITY_TEST(testI64, (int64_t)pow(static_cast<double>(2LL), 32) + 1); | |
582 | BASETYPE_IDENTITY_TEST(testI64, (int64_t)-pow(static_cast<double>(2LL), 32) - 1); | |
583 | BASETYPE_IDENTITY_TEST(testI64, (numeric_limits<int64_t>::max)()); | |
584 | BASETYPE_IDENTITY_TEST(testI64, (numeric_limits<int64_t>::min)()); | |
585 | ||
586 | /** | |
587 | * DOUBLE TEST | |
588 | */ | |
589 | // Comparing double values with plain equality because Thrift handles full precision of double | |
590 | BASETYPE_IDENTITY_TEST(testDouble, 0.0); | |
591 | BASETYPE_IDENTITY_TEST(testDouble, -1.0); | |
592 | BASETYPE_IDENTITY_TEST(testDouble, -5.2098523); | |
593 | BASETYPE_IDENTITY_TEST(testDouble, -0.000341012439638598279); | |
594 | BASETYPE_IDENTITY_TEST(testDouble, pow(static_cast<double>(2), 32)); | |
595 | BASETYPE_IDENTITY_TEST(testDouble, pow(static_cast<double>(2), 32) + 1); | |
596 | BASETYPE_IDENTITY_TEST(testDouble, pow(static_cast<double>(2), 53) - 1); | |
597 | BASETYPE_IDENTITY_TEST(testDouble, -pow(static_cast<double>(2), 32)); | |
598 | BASETYPE_IDENTITY_TEST(testDouble, -pow(static_cast<double>(2), 32) - 1); | |
599 | BASETYPE_IDENTITY_TEST(testDouble, -pow(static_cast<double>(2), 53) + 1); | |
600 | ||
601 | try { | |
602 | double expected = pow(static_cast<double>(10), 307); | |
603 | cout << "testDouble(" << expected << ") = " << flush; | |
604 | double actual = testClient.testDouble(expected); | |
605 | cout << "(" << actual << ")" << endl; | |
606 | if (expected - actual > pow(static_cast<double>(10), 292)) { | |
607 | cout << "*** FAILED ***" << endl | |
608 | << "Expected: " << expected << " but got: " << actual << endl; | |
609 | } | |
610 | } catch (TTransportException&) { | |
611 | throw; | |
612 | } catch (exception& ex) { | |
613 | cout << "*** FAILED ***" << endl << ex.what() << endl; | |
614 | return_code |= ERR_BASETYPES; | |
615 | } | |
616 | ||
617 | try { | |
618 | double expected = pow(static_cast<double>(10), -292); | |
619 | cout << "testDouble(" << expected << ") = " << flush; | |
620 | double actual = testClient.testDouble(expected); | |
621 | cout << "(" << actual << ")" << endl; | |
622 | if (expected - actual > pow(static_cast<double>(10), -307)) { | |
623 | cout << "*** FAILED ***" << endl | |
624 | << "Expected: " << expected << " but got: " << actual << endl; | |
625 | } | |
626 | } catch (TTransportException&) { | |
627 | throw; | |
628 | } catch (exception& ex) { | |
629 | cout << "*** FAILED ***" << endl << ex.what() << endl; | |
630 | return_code |= ERR_BASETYPES; | |
631 | } | |
632 | ||
633 | /** | |
634 | * BINARY TEST | |
635 | */ | |
636 | for (string::size_type i = 0; i < 131073 && !return_code; ) { | |
637 | return_code |= binary_test(testClient, i); | |
638 | if (i > 0) { i *= 2; } else { ++i; } | |
639 | } | |
640 | ||
641 | ||
642 | /** | |
643 | * STRUCT TEST | |
644 | */ | |
645 | cout << "testStruct({\"Zero\", 1, -3, -5})" << flush; | |
646 | Xtruct out; | |
647 | out.string_thing = "Zero"; | |
648 | out.byte_thing = 1; | |
649 | out.i32_thing = -3; | |
650 | out.i64_thing = -5; | |
651 | Xtruct in; | |
652 | testClient.testStruct(in, out); | |
653 | printf(" = {\"%s\", %d, %d, %" PRId64 "}\n", | |
654 | in.string_thing.c_str(), | |
655 | (int)in.byte_thing, | |
656 | in.i32_thing, | |
657 | in.i64_thing); | |
658 | if (in != out) { | |
659 | cout << "*** FAILED ***" << endl; | |
660 | return_code |= ERR_STRUCTS; | |
661 | } | |
662 | ||
663 | /** | |
664 | * NESTED STRUCT TEST | |
665 | */ | |
666 | cout << "testNest({1, {\"Zero\", 1, -3, -5}), 5}" << flush; | |
667 | Xtruct2 out2; | |
668 | out2.byte_thing = 1; | |
669 | out2.struct_thing = out; | |
670 | out2.i32_thing = 5; | |
671 | Xtruct2 in2; | |
672 | testClient.testNest(in2, out2); | |
673 | in = in2.struct_thing; | |
674 | printf(" = {%d, {\"%s\", %d, %d, %" PRId64 "}, %d}\n", | |
675 | in2.byte_thing, | |
676 | in.string_thing.c_str(), | |
677 | (int)in.byte_thing, | |
678 | in.i32_thing, | |
679 | in.i64_thing, | |
680 | in2.i32_thing); | |
681 | if (in2 != out2) { | |
682 | cout << "*** FAILED ***" << endl; | |
683 | return_code |= ERR_STRUCTS; | |
684 | } | |
685 | ||
686 | /** | |
687 | * MAP TEST | |
688 | */ | |
689 | map<int32_t, int32_t> mapout; | |
690 | for (int32_t i = 0; i < 5; ++i) { | |
691 | mapout.insert(make_pair(i, i - 10)); | |
692 | } | |
693 | cout << "testMap({" << flush; | |
694 | map<int32_t, int32_t>::const_iterator m_iter; | |
695 | bool first = true; | |
696 | for (m_iter = mapout.begin(); m_iter != mapout.end(); ++m_iter) { | |
697 | if (first) { | |
698 | first = false; | |
699 | } else { | |
700 | cout << ","; | |
701 | } | |
702 | cout << m_iter->first << " => " << m_iter->second; | |
703 | } | |
704 | cout << "})"; | |
705 | map<int32_t, int32_t> mapin; | |
706 | testClient.testMap(mapin, mapout); | |
707 | cout << " = {"; | |
708 | first = true; | |
709 | for (m_iter = mapin.begin(); m_iter != mapin.end(); ++m_iter) { | |
710 | if (first) { | |
711 | first = false; | |
712 | } else { | |
713 | cout << ","; | |
714 | } | |
715 | cout << m_iter->first << " => " << m_iter->second; | |
716 | } | |
717 | cout << "}" << endl; | |
718 | if (mapin != mapout) { | |
719 | cout << "*** FAILED ***" << endl; | |
720 | return_code |= ERR_CONTAINERS; | |
721 | } | |
722 | ||
723 | /** | |
724 | * STRING MAP TEST | |
725 | */ | |
726 | cout << "testStringMap({a => 2, b => blah, some => thing}) = {" << flush; | |
727 | map<string, string> smapin; | |
728 | map<string, string> smapout; | |
729 | smapin["a"] = "2"; | |
730 | smapin["b"] = "blah"; | |
731 | smapin["some"] = "thing"; | |
732 | try { | |
733 | testClient.testStringMap(smapout, smapin); | |
734 | first = true; | |
735 | for (map<string, string>::const_iterator it = smapout.begin(); it != smapout.end(); ++it) { | |
736 | if (first) | |
737 | cout << ","; | |
738 | else | |
739 | first = false; | |
740 | cout << it->first << " => " << it->second; | |
741 | } | |
742 | cout << "}" << endl; | |
743 | if (smapin != smapout) { | |
744 | cout << "*** FAILED ***" << endl; | |
745 | return_code |= ERR_CONTAINERS; | |
746 | } | |
747 | } catch (TTransportException&) { | |
748 | throw; | |
749 | } catch (exception& ex) { | |
750 | cout << "*** FAILED ***" << endl << ex.what() << endl; | |
751 | return_code |= ERR_CONTAINERS; | |
752 | } | |
753 | ||
754 | /** | |
755 | * SET TEST | |
756 | */ | |
757 | set<int32_t> setout; | |
758 | for (int32_t i = -2; i < 3; ++i) { | |
759 | setout.insert(i); | |
760 | } | |
761 | cout << "testSet({" << flush; | |
762 | set<int32_t>::const_iterator s_iter; | |
763 | first = true; | |
764 | for (s_iter = setout.begin(); s_iter != setout.end(); ++s_iter) { | |
765 | if (first) { | |
766 | first = false; | |
767 | } else { | |
768 | cout << ","; | |
769 | } | |
770 | cout << *s_iter; | |
771 | } | |
772 | cout << "})"; | |
773 | set<int32_t> setin; | |
774 | testClient.testSet(setin, setout); | |
775 | cout << " = {"; | |
776 | first = true; | |
777 | for (s_iter = setin.begin(); s_iter != setin.end(); ++s_iter) { | |
778 | if (first) { | |
779 | first = false; | |
780 | } else { | |
781 | cout << ","; | |
782 | } | |
783 | cout << *s_iter; | |
784 | } | |
785 | cout << "}" << endl; | |
786 | if (setin != setout) { | |
787 | cout << "*** FAILED ***" << endl; | |
788 | return_code |= ERR_CONTAINERS; | |
789 | } | |
790 | ||
791 | /** | |
792 | * LIST TEST | |
793 | */ | |
794 | cout << "testList(empty)" << flush; | |
795 | try { | |
796 | vector<int32_t> listout; | |
797 | testClient.testList(listout, vector<int32_t>()); | |
798 | if (!listout.empty()) { | |
799 | cout << "*** FAILED ***" << endl; | |
800 | cout << "invalid length: " << listout.size() << endl; | |
801 | return_code |= ERR_CONTAINERS; | |
802 | } | |
803 | } catch (TTransportException&) { | |
804 | throw; | |
805 | } catch (exception& ex) { | |
806 | cout << "*** FAILED ***" << endl << ex.what() << endl; | |
807 | return_code |= ERR_CONTAINERS; | |
808 | } | |
809 | try { | |
810 | vector<int32_t> listout; | |
811 | for (int32_t i = -2; i < 3; ++i) { | |
812 | listout.push_back(i); | |
813 | } | |
814 | cout << "testList({" << flush; | |
815 | vector<int32_t>::const_iterator l_iter; | |
816 | first = true; | |
817 | for (l_iter = listout.begin(); l_iter != listout.end(); ++l_iter) { | |
818 | if (first) { | |
819 | first = false; | |
820 | } else { | |
821 | cout << ","; | |
822 | } | |
823 | cout << *l_iter; | |
824 | } | |
825 | cout << "})"; | |
826 | vector<int32_t> listin; | |
827 | testClient.testList(listin, listout); | |
828 | cout << " = {"; | |
829 | first = true; | |
830 | for (l_iter = listin.begin(); l_iter != listin.end(); ++l_iter) { | |
831 | if (first) { | |
832 | first = false; | |
833 | } else { | |
834 | cout << ","; | |
835 | } | |
836 | cout << *l_iter; | |
837 | } | |
838 | cout << "}" << endl; | |
839 | if (listin != listout) { | |
840 | cout << "*** FAILED ***" << endl; | |
841 | return_code |= ERR_CONTAINERS; | |
842 | } | |
843 | } catch (TTransportException&) { | |
844 | throw; | |
845 | } catch (exception& ex) { | |
846 | cout << "*** FAILED ***" << endl << ex.what() << endl; | |
847 | return_code |= ERR_CONTAINERS; | |
848 | } | |
849 | ||
850 | /** | |
851 | * ENUM TEST | |
852 | */ | |
853 | cout << "testEnum(ONE)" << flush; | |
854 | Numberz::type ret = testClient.testEnum(Numberz::ONE); | |
855 | cout << " = " << ret << endl; | |
856 | if (ret != Numberz::ONE) { | |
857 | cout << "*** FAILED ***" << endl; | |
858 | return_code |= ERR_STRUCTS; | |
859 | } | |
860 | ||
861 | cout << "testEnum(TWO)" << flush; | |
862 | ret = testClient.testEnum(Numberz::TWO); | |
863 | cout << " = " << ret << endl; | |
864 | if (ret != Numberz::TWO) { | |
865 | cout << "*** FAILED ***" << endl; | |
866 | return_code |= ERR_STRUCTS; | |
867 | } | |
868 | ||
869 | cout << "testEnum(THREE)" << flush; | |
870 | ret = testClient.testEnum(Numberz::THREE); | |
871 | cout << " = " << ret << endl; | |
872 | if (ret != Numberz::THREE) { | |
873 | cout << "*** FAILED ***" << endl; | |
874 | return_code |= ERR_STRUCTS; | |
875 | } | |
876 | ||
877 | cout << "testEnum(FIVE)" << flush; | |
878 | ret = testClient.testEnum(Numberz::FIVE); | |
879 | cout << " = " << ret << endl; | |
880 | if (ret != Numberz::FIVE) { | |
881 | cout << "*** FAILED ***" << endl; | |
882 | return_code |= ERR_STRUCTS; | |
883 | } | |
884 | ||
885 | cout << "testEnum(EIGHT)" << flush; | |
886 | ret = testClient.testEnum(Numberz::EIGHT); | |
887 | cout << " = " << ret << endl; | |
888 | if (ret != Numberz::EIGHT) { | |
889 | cout << "*** FAILED ***" << endl; | |
890 | return_code |= ERR_STRUCTS; | |
891 | } | |
892 | ||
893 | /** | |
894 | * TYPEDEF TEST | |
895 | */ | |
896 | cout << "testTypedef(309858235082523)" << flush; | |
897 | UserId uid = testClient.testTypedef(309858235082523LL); | |
898 | cout << " = " << uid << endl; | |
899 | if (uid != 309858235082523LL) { | |
900 | cout << "*** FAILED ***" << endl; | |
901 | return_code |= ERR_STRUCTS; | |
902 | } | |
903 | ||
904 | /** | |
905 | * NESTED MAP TEST | |
906 | */ | |
907 | cout << "testMapMap(1)" << flush; | |
908 | map<int32_t, map<int32_t, int32_t> > mm; | |
909 | testClient.testMapMap(mm, 1); | |
910 | cout << " = {"; | |
911 | map<int32_t, map<int32_t, int32_t> >::const_iterator mi; | |
912 | for (mi = mm.begin(); mi != mm.end(); ++mi) { | |
913 | printf("%d => {", mi->first); | |
914 | map<int32_t, int32_t>::const_iterator mi2; | |
915 | for (mi2 = mi->second.begin(); mi2 != mi->second.end(); ++mi2) { | |
916 | cout << mi2->first << " => " << mi2->second; | |
917 | } | |
918 | cout << "}, "; | |
919 | } | |
920 | cout << "}" << endl; | |
921 | if (mm.size() != 2 || | |
922 | mm[-4][-4] != -4 || | |
923 | mm[-4][-3] != -3 || | |
924 | mm[-4][-2] != -2 || | |
925 | mm[-4][-1] != -1 || | |
926 | mm[4][4] != 4 || | |
927 | mm[4][3] != 3 || | |
928 | mm[4][2] != 2 || | |
929 | mm[4][1] != 1) { | |
930 | cout << "*** FAILED ***" << endl; | |
931 | return_code |= ERR_CONTAINERS; | |
932 | } | |
933 | ||
934 | /** | |
935 | * INSANITY TEST | |
936 | */ | |
937 | if (!noinsane) { | |
938 | Insanity insane; | |
939 | insane.userMap.insert(make_pair(Numberz::FIVE, 5)); | |
940 | insane.userMap.insert(make_pair(Numberz::EIGHT, 8)); | |
941 | Xtruct truck; | |
942 | truck.string_thing = "Goodbye4"; | |
943 | truck.byte_thing = 4; | |
944 | truck.i32_thing = 4; | |
945 | truck.i64_thing = 4; | |
946 | Xtruct truck2; | |
947 | truck2.string_thing = "Hello2"; | |
948 | truck2.byte_thing = 2; | |
949 | truck2.i32_thing = 2; | |
950 | truck2.i64_thing = 2; | |
951 | insane.xtructs.push_back(truck); | |
952 | insane.xtructs.push_back(truck2); | |
953 | cout << "testInsanity()" << flush; | |
954 | map<UserId, map<Numberz::type, Insanity> > whoa; | |
955 | testClient.testInsanity(whoa, insane); | |
956 | cout << " = {"; | |
957 | map<UserId, map<Numberz::type, Insanity> >::const_iterator i_iter; | |
958 | for (i_iter = whoa.begin(); i_iter != whoa.end(); ++i_iter) { | |
959 | printf("%" PRId64 " => {", i_iter->first); | |
960 | map<Numberz::type, Insanity>::const_iterator i2_iter; | |
961 | for (i2_iter = i_iter->second.begin(); i2_iter != i_iter->second.end(); ++i2_iter) { | |
962 | printf("%d => {", i2_iter->first); | |
963 | map<Numberz::type, UserId> userMap = i2_iter->second.userMap; | |
964 | map<Numberz::type, UserId>::const_iterator um; | |
965 | cout << "{"; | |
966 | for (um = userMap.begin(); um != userMap.end(); ++um) { | |
967 | cout << um->first << " => " << um->second; | |
968 | } | |
969 | cout << "}, "; | |
970 | ||
971 | vector<Xtruct> xtructs = i2_iter->second.xtructs; | |
972 | vector<Xtruct>::const_iterator x; | |
973 | cout << "{"; | |
974 | for (x = xtructs.begin(); x != xtructs.end(); ++x) { | |
975 | printf("{\"%s\", %d, %d, %" PRId64 "}, ", | |
976 | x->string_thing.c_str(), | |
977 | (int)x->byte_thing, | |
978 | x->i32_thing, | |
979 | x->i64_thing); | |
980 | } | |
981 | cout << "}"; | |
982 | ||
983 | cout << "}, "; | |
984 | } | |
985 | cout << "}, "; | |
986 | } | |
987 | cout << "}" << endl; | |
988 | bool failed = false; | |
989 | map<UserId, map<Numberz::type, Insanity> >::const_iterator it1 = whoa.find(UserId(1)); | |
990 | if (whoa.size() != 2) { | |
991 | failed = true; | |
992 | } | |
993 | if (it1 == whoa.end()) { | |
994 | failed = true; | |
995 | } else { | |
996 | auto it12 = it1->second.find(Numberz::TWO); | |
997 | if (it12 == it1->second.end() || it12->second != insane) { | |
998 | failed = true; | |
999 | } | |
1000 | auto it13 = it1->second.find(Numberz::THREE); | |
1001 | if (it13 == it1->second.end() || it13->second != insane) { | |
1002 | failed = true; | |
1003 | } | |
1004 | } | |
1005 | map<UserId, map<Numberz::type, Insanity> >::const_iterator it2 = whoa.find(UserId(2)); | |
1006 | if (it2 == whoa.end()) { | |
1007 | failed = true; | |
1008 | } else { | |
1009 | auto it26 = it2->second.find(Numberz::SIX); | |
1010 | if (it26 == it2->second.end() || it26->second != Insanity()) { | |
1011 | failed = true; | |
1012 | } | |
1013 | } | |
1014 | if (failed) { | |
1015 | cout << "*** FAILED ***" << endl; | |
1016 | return_code |= ERR_STRUCTS; | |
1017 | } | |
1018 | } | |
1019 | ||
1020 | /** | |
1021 | * MULTI TEST | |
1022 | */ | |
1023 | cout << "testMulti()" << endl; | |
1024 | try { | |
1025 | map<int16_t, string> mul_map; | |
1026 | Xtruct mul_result; | |
1027 | mul_map[1] = "blah"; | |
1028 | mul_map[2] = "thing"; | |
1029 | testClient.testMulti(mul_result, 42, 4242, 424242, mul_map, Numberz::EIGHT, UserId(24)); | |
1030 | Xtruct xxs; | |
1031 | xxs.string_thing = "Hello2"; | |
1032 | xxs.byte_thing = 42; | |
1033 | xxs.i32_thing = 4242; | |
1034 | xxs.i64_thing = 424242; | |
1035 | if (mul_result != xxs) { | |
1036 | cout << "*** FAILED ***" << endl; | |
1037 | return_code |= ERR_STRUCTS; | |
1038 | } | |
1039 | } catch (TTransportException&) { | |
1040 | throw; | |
1041 | } catch (exception& ex) { | |
1042 | cout << "*** FAILED ***" << endl << ex.what() << endl; | |
1043 | return_code |= ERR_STRUCTS; | |
1044 | } | |
1045 | ||
1046 | /* test exception */ | |
1047 | ||
1048 | try { | |
1049 | cout << "testClient.testException(\"Xception\") =>" << flush; | |
1050 | testClient.testException("Xception"); | |
1051 | cout << " void\n*** FAILED ***" << endl; | |
1052 | return_code |= ERR_EXCEPTIONS; | |
1053 | ||
1054 | } catch (Xception& e) { | |
1055 | printf(" {%u, \"%s\"}\n", e.errorCode, e.message.c_str()); | |
1056 | } | |
1057 | ||
1058 | try { | |
1059 | cout << "testClient.testException(\"TException\") =>" << flush; | |
1060 | testClient.testException("TException"); | |
1061 | cout << " void\n*** FAILED ***" << endl; | |
1062 | return_code |= ERR_EXCEPTIONS; | |
1063 | ||
1064 | } catch (const TException&) { | |
1065 | cout << " Caught TException" << endl; | |
1066 | } | |
1067 | ||
1068 | try { | |
1069 | cout << "testClient.testException(\"success\") =>" << flush; | |
1070 | testClient.testException("success"); | |
1071 | cout << " void" << endl; | |
1072 | } catch (exception & ex) { \ | |
1073 | cout << "*** FAILED ***" << endl << ex.what() << endl; | |
1074 | return_code |= ERR_EXCEPTIONS; | |
1075 | } | |
1076 | ||
1077 | /* test multi exception */ | |
1078 | ||
1079 | try { | |
1080 | cout << "testClient.testMultiException(\"Xception\", \"test 1\") =>" << flush; | |
1081 | Xtruct result; | |
1082 | testClient.testMultiException(result, "Xception", "test 1"); | |
1083 | cout << " result\n*** FAILED ***" << endl; | |
1084 | return_code |= ERR_EXCEPTIONS; | |
1085 | } catch (Xception& e) { | |
1086 | printf(" {%u, \"%s\"}\n", e.errorCode, e.message.c_str()); | |
1087 | } | |
1088 | ||
1089 | try { | |
1090 | cout << "testClient.testMultiException(\"Xception2\", \"test 2\") =>" << flush; | |
1091 | Xtruct result; | |
1092 | testClient.testMultiException(result, "Xception2", "test 2"); | |
1093 | cout << " result\n*** FAILED ***" << endl; | |
1094 | return_code |= ERR_EXCEPTIONS; | |
1095 | ||
1096 | } catch (Xception2& e) { | |
1097 | printf(" {%u, {\"%s\"}}\n", e.errorCode, e.struct_thing.string_thing.c_str()); | |
1098 | } | |
1099 | ||
1100 | try { | |
1101 | cout << "testClient.testMultiException(\"success\", \"test 3\") =>" << flush; | |
1102 | Xtruct result; | |
1103 | testClient.testMultiException(result, "success", "test 3"); | |
1104 | printf(" {{\"%s\"}}\n", result.string_thing.c_str()); | |
1105 | } catch (exception & ex) { \ | |
1106 | cout << "*** FAILED ***" << endl << ex.what() << endl; | |
1107 | return_code |= ERR_EXCEPTIONS; | |
1108 | } | |
1109 | ||
1110 | /* test oneway void */ | |
1111 | { | |
1112 | cout << "testClient.testOneway(1) =>" << flush; | |
1113 | uint64_t startOneway = now(); | |
1114 | testClient.testOneway(1); | |
1115 | uint64_t elapsed = now() - startOneway; | |
1116 | if (elapsed > 200 * 1000) { // 0.2 seconds | |
1117 | printf("*** FAILED *** - took %.2f ms\n", (double)elapsed / 1000.0); | |
1118 | return_code |= ERR_BASETYPES; | |
1119 | } else { | |
1120 | printf(" success - took %.2f ms\n", (double)elapsed / 1000.0); | |
1121 | } | |
1122 | } | |
1123 | ||
1124 | /** | |
1125 | * redo a simple test after the oneway to make sure we aren't "off by one" -- | |
1126 | * if the server treated oneway void like normal void, this next test will | |
1127 | * fail since it will get the void confirmation rather than the correct | |
1128 | * result. In this circumstance, the client will throw the exception: | |
1129 | * | |
1130 | * TApplicationException: Wrong method namea | |
1131 | */ | |
1132 | /** | |
1133 | * I32 TEST | |
1134 | */ | |
1135 | cout << "re-test testI32(-1)" << flush; | |
1136 | int i32 = testClient.testI32(-1); | |
1137 | cout << " = " << i32 << endl; | |
1138 | if (i32 != -1) | |
1139 | return_code |= ERR_BASETYPES; | |
1140 | ||
1141 | cout << endl << "All tests done." << endl << flush; | |
1142 | ||
1143 | uint64_t stop = now(); | |
1144 | uint64_t tot = stop - start; | |
1145 | ||
1146 | cout << "Total time: " << stop - start << " us" << endl; | |
1147 | ||
1148 | time_tot += tot; | |
1149 | if (time_min == 0 || tot < time_min) { | |
1150 | time_min = tot; | |
1151 | } | |
1152 | if (tot > time_max) { | |
1153 | time_max = tot; | |
1154 | } | |
1155 | ||
1156 | cout << flush; | |
1157 | transport->close(); | |
1158 | } | |
1159 | ||
1160 | ||
1161 | uint64_t time_avg = time_tot / numTests; | |
1162 | ||
1163 | cout << "Min time: " << time_min << " us" << endl; | |
1164 | cout << "Max time: " << time_max << " us" << endl; | |
1165 | cout << "Avg time: " << time_avg << " us" << endl; | |
1166 | ||
1167 | return return_code; | |
1168 | } | |
1169 | ||
1170 | void binary_fill(std::string& str, string::size_type siz) | |
1171 | { | |
1172 | static const signed char bin_data[256] | |
1173 | = {-128, -127, -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, -116, -115, -114, | |
1174 | -113, -112, -111, -110, -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, -99, | |
1175 | -98, -97, -96, -95, -94, -93, -92, -91, -90, -89, -88, -87, -86, -85, -84, | |
1176 | -83, -82, -81, -80, -79, -78, -77, -76, -75, -74, -73, -72, -71, -70, -69, | |
1177 | -68, -67, -66, -65, -64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54, | |
1178 | -53, -52, -51, -50, -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, -39, | |
1179 | -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28, -27, -26, -25, -24, | |
1180 | -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, | |
1181 | -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, | |
1182 | 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, | |
1183 | 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, | |
1184 | 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, | |
1185 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, | |
1186 | 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, | |
1187 | 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, | |
1188 | 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, | |
1189 | 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, | |
1190 | 127}; | |
1191 | ||
1192 | str.resize(siz); | |
1193 | char *ptr = &str[0]; | |
1194 | string::size_type pos = 0; | |
1195 | for (string::size_type i = 0; i < siz; ++i) | |
1196 | { | |
1197 | if (pos == 255) { pos = 0; } else { ++pos; } | |
1198 | *ptr++ = bin_data[pos]; | |
1199 | } | |
1200 | } | |
1201 | ||
1202 | int binary_test(ThriftTestClient& testClient, string::size_type siz) | |
1203 | { | |
1204 | string bin_request; | |
1205 | string bin_result; | |
1206 | ||
1207 | cout << "testBinary(siz = " << siz << ")" << endl; | |
1208 | binary_fill(bin_request, siz); | |
1209 | try { | |
1210 | testClient.testBinary(bin_result, bin_request); | |
1211 | ||
1212 | if (bin_request.size() != bin_result.size()) { | |
1213 | cout << "*** FAILED: request size " << bin_request.size() << "; result size " << bin_result.size() << endl; | |
1214 | return ERR_BASETYPES; | |
1215 | } | |
1216 | ||
1217 | for (string::size_type i = 0; i < siz; ++i) { | |
1218 | if (bin_request.at(i) != bin_result.at(i)) { | |
1219 | cout << "*** FAILED: at position " << i << " request[i] is h" << hex << bin_request.at(i) << " result[i] is h" << hex << bin_result.at(i) << endl; | |
1220 | return ERR_BASETYPES; | |
1221 | } | |
1222 | } | |
1223 | } catch (TTransportException&) { | |
1224 | throw; | |
1225 | } catch (exception& ex) { | |
1226 | cout << "*** FAILED ***" << endl << ex.what() << endl; | |
1227 | return ERR_BASETYPES; | |
1228 | } | |
1229 | ||
1230 | return 0; | |
1231 | } |