blob: fd53328b07b957e2f92237ee4f290ac17ec3b4b7 [file] [log] [blame]
Jake Farrellb95b0ff2012-03-22 21:49:10 +00001/*
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 */
19module thrift_test_client;
20
21import std.conv;
22import std.datetime;
23import std.exception : enforce;
24import std.getopt;
25import std.stdio;
26import std.string;
27import std.traits;
28import thrift.codegen.client;
29import thrift.protocol.base;
30import thrift.protocol.binary;
31import thrift.protocol.compact;
32import thrift.protocol.json;
33import thrift.transport.base;
34import thrift.transport.buffered;
35import thrift.transport.framed;
36import thrift.transport.http;
37import thrift.transport.socket;
38import thrift.transport.ssl;
39import thrift.util.hashset;
40
41import thrift_test_common;
42import thrift.test.ThriftTest;
43import thrift.test.ThriftTest_types;
44
45enum TransportType {
46 buffered,
47 framed,
48 http,
49 raw
50}
51
52TProtocol createProtocol(T)(T trans, ProtocolType type) {
53 final switch (type) {
54 case ProtocolType.binary:
55 return tBinaryProtocol(trans);
56 case ProtocolType.compact:
57 return tCompactProtocol(trans);
58 case ProtocolType.json:
59 return tJsonProtocol(trans);
60 }
61}
62
63void main(string[] args) {
64 string host = "localhost";
65 ushort port = 9090;
66 uint numTests = 1;
67 bool ssl;
68 ProtocolType protocolType;
69 TransportType transportType;
70 bool trace;
71
72 getopt(args,
73 "numTests|n", &numTests,
74 "protocol", &protocolType,
75 "ssl", &ssl,
76 "transport", &transportType,
77 "trace", &trace,
78 "host", (string _, string value) {
79 auto parts = split(value, ":");
80 if (parts.length > 1) {
81 // IPv6 addresses can contain colons, so take the last part for the
82 // port.
83 host = join(parts[0 .. $ - 1], ":");
84 port = to!ushort(parts[$ - 1]);
85 } else {
86 host = value;
87 }
88 }
89 );
90
91 TSocket socket;
92 if (ssl) {
93 auto sslContext = new TSSLContext();
94 sslContext.ciphers = "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH";
95 sslContext.authenticate = true;
96 sslContext.loadTrustedCertificates("./trusted-ca-certificate.pem");
97 socket = new TSSLSocket(sslContext, host, port);
98 } else {
99 socket = new TSocket(host, port);
100 }
101
102 TProtocol protocol;
103 final switch (transportType) {
104 case TransportType.buffered:
105 protocol = createProtocol(new TBufferedTransport(socket), protocolType);
106 break;
107 case TransportType.framed:
108 protocol = createProtocol(new TFramedTransport(socket), protocolType);
109 break;
110 case TransportType.http:
111 protocol = createProtocol(
112 new TClientHttpTransport(socket, host, "/service"), protocolType);
113 break;
114 case TransportType.raw:
115 protocol = createProtocol(socket, protocolType);
116 break;
117 }
118
119 auto client = tClient!ThriftTest(protocol);
120
121 ulong time_min;
122 ulong time_max;
123 ulong time_tot;
124
125 StopWatch sw;
126 foreach(test; 0 .. numTests) {
127 sw.start();
128
129 protocol.transport.open();
130
131 if (trace) writefln("Test #%s, connect %s:%s", test + 1, host, port);
132
133 if (trace) write("testVoid()");
134 client.testVoid();
135 if (trace) writeln(" = void");
136
137 if (trace) write("testString(\"Test\")");
138 string s = client.testString("Test");
139 if (trace) writefln(" = \"%s\"", s);
140 enforce(s == "Test");
141
142 if (trace) write("testByte(1)");
143 byte u8 = client.testByte(1);
144 if (trace) writefln(" = %s", u8);
145 enforce(u8 == 1);
146
147 if (trace) write("testI32(-1)");
148 int i32 = client.testI32(-1);
149 if (trace) writefln(" = %s", i32);
150 enforce(i32 == -1);
151
152 if (trace) write("testI64(-34359738368)");
153 long i64 = client.testI64(-34359738368L);
154 if (trace) writefln(" = %s", i64);
155 enforce(i64 == -34359738368L);
156
157 if (trace) write("testDouble(-5.2098523)");
158 double dub = client.testDouble(-5.2098523);
159 if (trace) writefln(" = %s", dub);
160 enforce(dub == -5.2098523);
161
Jens Geyer8bcfdd92014-12-14 03:14:26 +0100162 // TODO: add testBinary() call
163
Jake Farrellb95b0ff2012-03-22 21:49:10 +0000164 Xtruct out1;
165 out1.string_thing = "Zero";
166 out1.byte_thing = 1;
167 out1.i32_thing = -3;
168 out1.i64_thing = -5;
169 if (trace) writef("testStruct(%s)", out1);
170 auto in1 = client.testStruct(out1);
171 if (trace) writefln(" = %s", in1);
172 enforce(in1 == out1);
173
174 if (trace) write("testNest({1, {\"Zero\", 1, -3, -5}), 5}");
175 Xtruct2 out2;
176 out2.byte_thing = 1;
177 out2.struct_thing = out1;
178 out2.i32_thing = 5;
179 auto in2 = client.testNest(out2);
180 in1 = in2.struct_thing;
181 if (trace) writefln(" = {%s, {\"%s\", %s, %s, %s}, %s}", in2.byte_thing,
182 in1.string_thing, in1.byte_thing, in1.i32_thing, in1.i64_thing,
183 in2.i32_thing);
184 enforce(in2 == out2);
185
186 int[int] mapout;
187 for (int i = 0; i < 5; ++i) {
188 mapout[i] = i - 10;
189 }
190 if (trace) writef("testMap({%s})", mapout);
191 auto mapin = client.testMap(mapout);
192 if (trace) writefln(" = {%s}", mapin);
193 enforce(mapin == mapout);
194
195 auto setout = new HashSet!int;
196 for (int i = -2; i < 3; ++i) {
197 setout ~= i;
198 }
199 if (trace) writef("testSet(%s)", setout);
200 auto setin = client.testSet(setout);
201 if (trace) writefln(" = %s", setin);
202 enforce(setin == setout);
203
204 int[] listout;
205 for (int i = -2; i < 3; ++i) {
206 listout ~= i;
207 }
208 if (trace) writef("testList(%s)", listout);
209 auto listin = client.testList(listout);
210 if (trace) writefln(" = %s", listin);
211 enforce(listin == listout);
212
213 {
214 if (trace) write("testEnum(ONE)");
215 auto ret = client.testEnum(Numberz.ONE);
216 if (trace) writefln(" = %s", ret);
217 enforce(ret == Numberz.ONE);
218
219 if (trace) write("testEnum(TWO)");
220 ret = client.testEnum(Numberz.TWO);
221 if (trace) writefln(" = %s", ret);
222 enforce(ret == Numberz.TWO);
223
224 if (trace) write("testEnum(THREE)");
225 ret = client.testEnum(Numberz.THREE);
226 if (trace) writefln(" = %s", ret);
227 enforce(ret == Numberz.THREE);
228
229 if (trace) write("testEnum(FIVE)");
230 ret = client.testEnum(Numberz.FIVE);
231 if (trace) writefln(" = %s", ret);
232 enforce(ret == Numberz.FIVE);
233
234 if (trace) write("testEnum(EIGHT)");
235 ret = client.testEnum(Numberz.EIGHT);
236 if (trace) writefln(" = %s", ret);
237 enforce(ret == Numberz.EIGHT);
238 }
239
240 if (trace) write("testTypedef(309858235082523)");
241 UserId uid = client.testTypedef(309858235082523L);
242 if (trace) writefln(" = %s", uid);
243 enforce(uid == 309858235082523L);
244
245 if (trace) write("testMapMap(1)");
246 auto mm = client.testMapMap(1);
247 if (trace) writefln(" = {%s}", mm);
248 // Simply doing == doesn't seem to work for nested AAs.
249 foreach (key, value; mm) {
250 enforce(testMapMapReturn[key] == value);
251 }
252 foreach (key, value; testMapMapReturn) {
253 enforce(mm[key] == value);
254 }
255
256 Insanity insane;
257 insane.userMap[Numberz.FIVE] = 5000;
258 Xtruct truck;
259 truck.string_thing = "Truck";
260 truck.byte_thing = 8;
261 truck.i32_thing = 8;
262 truck.i64_thing = 8;
263 insane.xtructs ~= truck;
264 if (trace) write("testInsanity()");
265 auto whoa = client.testInsanity(insane);
266 if (trace) writefln(" = %s", whoa);
267
268 // Commented for now, this is cumbersome to write without opEqual getting
269 // called on AA comparison.
270 // enforce(whoa == testInsanityReturn);
271
272 {
273 try {
274 if (trace) write("client.testException(\"Xception\") =>");
275 client.testException("Xception");
276 if (trace) writeln(" void\nFAILURE");
277 throw new Exception("testException failed.");
278 } catch (Xception e) {
279 if (trace) writefln(" {%s, \"%s\"}", e.errorCode, e.message);
280 }
281
282 try {
283 if (trace) write("client.testException(\"success\") =>");
284 client.testException("success");
285 if (trace) writeln(" void");
286 } catch (Exception e) {
287 if (trace) writeln(" exception\nFAILURE");
288 throw new Exception("testException failed.");
289 }
290 }
291
292 {
293 try {
294 if (trace) write("client.testMultiException(\"Xception\", \"test 1\") =>");
295 auto result = client.testMultiException("Xception", "test 1");
296 if (trace) writeln(" result\nFAILURE");
297 throw new Exception("testMultiException failed.");
298 } catch (Xception e) {
299 if (trace) writefln(" {%s, \"%s\"}", e.errorCode, e.message);
300 }
301
302 try {
303 if (trace) write("client.testMultiException(\"Xception2\", \"test 2\") =>");
304 auto result = client.testMultiException("Xception2", "test 2");
305 if (trace) writeln(" result\nFAILURE");
306 throw new Exception("testMultiException failed.");
307 } catch (Xception2 e) {
308 if (trace) writefln(" {%s, {\"%s\"}}",
309 e.errorCode, e.struct_thing.string_thing);
310 }
311
312 try {
313 if (trace) writef("client.testMultiException(\"success\", \"test 3\") =>");
314 auto result = client.testMultiException("success", "test 3");
315 if (trace) writefln(" {{\"%s\"}}", result.string_thing);
316 } catch (Exception e) {
317 if (trace) writeln(" exception\nFAILURE");
318 throw new Exception("testMultiException failed.");
319 }
320 }
321
322 // Do not run oneway test when doing multiple iterations, as it blocks the
323 // server for three seconds.
324 if (numTests == 1) {
325 if (trace) writef("client.testOneway(3) =>");
326 auto onewayWatch = StopWatch(AutoStart.yes);
327 client.testOneway(3);
328 onewayWatch.stop();
329 if (onewayWatch.peek().msecs > 200) {
330 if (trace) {
331 writefln(" FAILURE - took %s ms", onewayWatch.peek().usecs / 1000.0);
332 }
333 throw new Exception("testOneway failed.");
334 } else {
335 if (trace) {
336 writefln(" success - took %s ms", onewayWatch.peek().usecs / 1000.0);
337 }
338 }
339
340 // Redo a simple test after the oneway to make sure we aren't "off by
341 // one", which would be the case if the server treated oneway methods
342 // like normal ones.
343 if (trace) write("re-test testI32(-1)");
344 i32 = client.testI32(-1);
345 if (trace) writefln(" = %s", i32);
346 }
347
348 // Time metering.
349 sw.stop();
350
351 immutable tot = sw.peek().usecs;
352 if (trace) writefln("Total time: %s us\n", tot);
353
354 time_tot += tot;
355 if (time_min == 0 || tot < time_min) {
356 time_min = tot;
357 }
358 if (tot > time_max) {
359 time_max = tot;
360 }
361 protocol.transport.close();
362
363 sw.reset();
364 }
365
366 writeln("All tests done.");
367
368 if (numTests > 1) {
369 auto time_avg = time_tot / numTests;
370 writefln("Min time: %s us", time_min);
371 writefln("Max time: %s us", time_max);
372 writefln("Avg time: %s us", time_avg);
373 }
374}