blob: ad4823f25c55d4a87aaa4903c858b6a1f37412c9 [file] [log] [blame]
Jake Farrell27274222011-11-10 20:32:44 +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 *)
19
20unit TestServer;
21
Roger Meier3bef8c22012-10-06 06:58:00 +000022{$WARN SYMBOL_PLATFORM OFF}
23
Jens Geyer06045cf2013-03-27 20:26:25 +020024{.$DEFINE RunEndless} // activate to interactively stress-test the server stop routines via Ctrl+C
25
Jake Farrell27274222011-11-10 20:32:44 +000026interface
27
28uses
Roger Meier3bef8c22012-10-06 06:58:00 +000029 Windows, SysUtils,
Jake Farrell27274222011-11-10 20:32:44 +000030 Generics.Collections,
31 Thrift.Console,
32 Thrift.Server,
33 Thrift.Transport,
Roger Meier3bef8c22012-10-06 06:58:00 +000034 Thrift.Transport.Pipes,
Jake Farrell27274222011-11-10 20:32:44 +000035 Thrift.Protocol,
36 Thrift.Protocol.JSON,
37 Thrift.Collections,
38 Thrift.Utils,
39 Thrift.Test,
40 Thrift,
41 TestConstants,
Jens Geyer01640402013-09-25 21:12:21 +020042 TestServerEvents,
Jake Farrell27274222011-11-10 20:32:44 +000043 Contnrs;
44
45type
46 TTestServer = class
47 public
48 type
49
50 ITestHandler = interface( TThriftTest.Iface )
Roger Meier333bbf32012-01-08 21:51:08 +000051 procedure SetServer( const AServer : IServer );
Jens Geyer06045cf2013-03-27 20:26:25 +020052 procedure TestStop;
Jake Farrell27274222011-11-10 20:32:44 +000053 end;
54
55 TTestHandlerImpl = class( TInterfacedObject, ITestHandler )
56 private
57 FServer : IServer;
58 protected
59 procedure testVoid();
Roger Meier333bbf32012-01-08 21:51:08 +000060 function testString(const thing: string): string;
Jake Farrell7ae13e12011-10-18 14:35:26 +000061 function testByte(thing: ShortInt): ShortInt;
62 function testI32(thing: Integer): Integer;
Roger Meier333bbf32012-01-08 21:51:08 +000063 function testI64(const thing: Int64): Int64;
64 function testDouble(const thing: Double): Double;
Jens Geyerfd1b3582014-12-13 23:42:58 +010065 function testBinary(const thing: TBytes): TBytes;
Roger Meier333bbf32012-01-08 21:51:08 +000066 function testStruct(const thing: IXtruct): IXtruct;
67 function testNest(const thing: IXtruct2): IXtruct2;
68 function testMap(const thing: IThriftDictionary<Integer, Integer>): IThriftDictionary<Integer, Integer>;
69 function testStringMap(const thing: IThriftDictionary<string, string>): IThriftDictionary<string, string>;
70 function testSet(const thing: IHashSet<Integer>): IHashSet<Integer>;
71 function testList(const thing: IThriftList<Integer>): IThriftList<Integer>;
Jake Farrell7ae13e12011-10-18 14:35:26 +000072 function testEnum(thing: TNumberz): TNumberz;
Roger Meier333bbf32012-01-08 21:51:08 +000073 function testTypedef(const thing: Int64): Int64;
Jake Farrell7ae13e12011-10-18 14:35:26 +000074 function testMapMap(hello: Integer): IThriftDictionary<Integer, IThriftDictionary<Integer, Integer>>;
Roger Meier333bbf32012-01-08 21:51:08 +000075 function testInsanity(const argument: IInsanity): IThriftDictionary<Int64, IThriftDictionary<TNumberz, IInsanity>>;
76 function testMulti(arg0: ShortInt; arg1: Integer; const arg2: Int64; const arg3: IThriftDictionary<SmallInt, string>; arg4: TNumberz; const arg5: Int64): IXtruct;
77 procedure testException(const arg: string);
78 function testMultiException(const arg0: string; const arg1: string): IXtruct;
Jake Farrell7ae13e12011-10-18 14:35:26 +000079 procedure testOneway(secondsToSleep: Integer);
Jake Farrell27274222011-11-10 20:32:44 +000080
Jens Geyer06045cf2013-03-27 20:26:25 +020081 procedure TestStop;
Roger Meier333bbf32012-01-08 21:51:08 +000082 procedure SetServer( const AServer : IServer );
Jake Farrell27274222011-11-10 20:32:44 +000083 end;
84
Jens Geyerf8a1b7a2014-09-24 00:26:46 +020085 class procedure PrintCmdLineHelp;
86 class procedure InvalidArgs;
87
Jens Geyer06045cf2013-03-27 20:26:25 +020088 class procedure LaunchAnonPipeChild( const app : string; const transport : IAnonymousPipeServerTransport);
Roger Meier333bbf32012-01-08 21:51:08 +000089 class procedure Execute( const args: array of string);
Jake Farrell27274222011-11-10 20:32:44 +000090 end;
91
92implementation
93
Jens Geyer06045cf2013-03-27 20:26:25 +020094
95var g_Handler : TTestServer.ITestHandler = nil;
96
97
98function MyConsoleEventHandler( dwCtrlType : DWORD) : BOOL; stdcall;
99// Note that this Handler procedure is called from another thread
100var handler : TTestServer.ITestHandler;
101begin
102 result := TRUE;
103 try
104 case dwCtrlType of
105 CTRL_C_EVENT : Console.WriteLine( 'Ctrl+C pressed');
106 CTRL_BREAK_EVENT : Console.WriteLine( 'Ctrl+Break pressed');
107 CTRL_CLOSE_EVENT : Console.WriteLine( 'Received CloseTask signal');
108 CTRL_LOGOFF_EVENT : Console.WriteLine( 'Received LogOff signal');
109 CTRL_SHUTDOWN_EVENT : Console.WriteLine( 'Received Shutdown signal');
110 else
111 Console.WriteLine( 'Received console event #'+IntToStr(Integer(dwCtrlType)));
112 end;
113
114 handler := g_Handler;
115 if handler <> nil then handler.TestStop;
116
117 except
118 // catch all
119 end;
120end;
121
122
Jake Farrell27274222011-11-10 20:32:44 +0000123{ TTestServer.TTestHandlerImpl }
124
Roger Meier333bbf32012-01-08 21:51:08 +0000125procedure TTestServer.TTestHandlerImpl.SetServer( const AServer: IServer);
Jake Farrell27274222011-11-10 20:32:44 +0000126begin
127 FServer := AServer;
128end;
129
130function TTestServer.TTestHandlerImpl.testByte(thing: ShortInt): ShortInt;
131begin
132 Console.WriteLine('testByte("' + IntToStr( thing) + '")');
133 Result := thing;
134end;
135
Roger Meier333bbf32012-01-08 21:51:08 +0000136function TTestServer.TTestHandlerImpl.testDouble( const thing: Double): Double;
Jake Farrell27274222011-11-10 20:32:44 +0000137begin
138 Console.WriteLine('testDouble("' + FloatToStr( thing ) + '")');
139 Result := thing;
140end;
141
Jens Geyerfd1b3582014-12-13 23:42:58 +0100142function TTestServer.TTestHandlerImpl.testBinary(const thing: TBytes): TBytes;
143begin
144 Console.WriteLine('testBinary("' + BytesToHex( thing ) + '")');
145 Result := thing;
146end;
147
Jake Farrell27274222011-11-10 20:32:44 +0000148function TTestServer.TTestHandlerImpl.testEnum(thing: TNumberz): TNumberz;
149begin
150 Console.WriteLine('testEnum(' + IntToStr( Integer( thing)) + ')');
151 Result := thing;
152end;
153
Roger Meier333bbf32012-01-08 21:51:08 +0000154procedure TTestServer.TTestHandlerImpl.testException(const arg: string);
Jake Farrell27274222011-11-10 20:32:44 +0000155begin
156 Console.WriteLine('testException(' + arg + ')');
157 if ( arg = 'Xception') then
158 begin
Roger Meierbb6de7a2012-05-04 23:35:45 +0000159 raise TXception.Create( 1001, arg);
Jake Farrell27274222011-11-10 20:32:44 +0000160 end;
Roger Meierbb6de7a2012-05-04 23:35:45 +0000161
162 if (arg = 'TException') then
163 begin
164 raise TException.Create('');
165 end;
166
167 // else do not throw anything
Jake Farrell27274222011-11-10 20:32:44 +0000168end;
169
170function TTestServer.TTestHandlerImpl.testI32(thing: Integer): Integer;
171begin
172 Console.WriteLine('testI32("' + IntToStr( thing) + '")');
173 Result := thing;
174end;
175
Roger Meier333bbf32012-01-08 21:51:08 +0000176function TTestServer.TTestHandlerImpl.testI64( const thing: Int64): Int64;
Jake Farrell27274222011-11-10 20:32:44 +0000177begin
178 Console.WriteLine('testI64("' + IntToStr( thing) + '")');
179 Result := thing;
180end;
181
182function TTestServer.TTestHandlerImpl.testInsanity(
Roger Meier333bbf32012-01-08 21:51:08 +0000183 const argument: IInsanity): IThriftDictionary<Int64, IThriftDictionary<TNumberz, IInsanity>>;
Jake Farrell27274222011-11-10 20:32:44 +0000184var
185 hello, goodbye : IXtruct;
186 crazy : IInsanity;
187 looney : IInsanity;
188 first_map : IThriftDictionary<TNumberz, IInsanity>;
189 second_map : IThriftDictionary<TNumberz, IInsanity>;
190 insane : IThriftDictionary<Int64, IThriftDictionary<TNumberz, IInsanity>>;
191
192begin
193
194 Console.WriteLine('testInsanity()');
195 hello := TXtructImpl.Create;
Roger Meierbb6de7a2012-05-04 23:35:45 +0000196 hello.String_thing := 'Hello2';
Jake Farrell27274222011-11-10 20:32:44 +0000197 hello.Byte_thing := 2;
198 hello.I32_thing := 2;
199 hello.I64_thing := 2;
200
201 goodbye := TXtructImpl.Create;
202 goodbye.String_thing := 'Goodbye4';
203 goodbye.Byte_thing := 4;
204 goodbye.I32_thing := 4;
205 goodbye.I64_thing := 4;
206
207 crazy := TInsanityImpl.Create;
208 crazy.UserMap := TThriftDictionaryImpl<TNumberz, Int64>.Create;
209 crazy.UserMap.AddOrSetValue( TNumberz.EIGHT, 8);
210 crazy.Xtructs := TThriftListImpl<IXtruct>.Create;
211 crazy.Xtructs.Add(goodbye);
212
213 looney := TInsanityImpl.Create;
214 crazy.UserMap.AddOrSetValue( TNumberz.FIVE, 5);
215 crazy.Xtructs.Add(hello);
216
217 first_map := TThriftDictionaryImpl<TNumberz, IInsanity>.Create;
218 second_map := TThriftDictionaryImpl<TNumberz, IInsanity>.Create;
219
Roger Meierbb6de7a2012-05-04 23:35:45 +0000220 first_map.AddOrSetValue( TNumberz.TWO, crazy);
Jake Farrell27274222011-11-10 20:32:44 +0000221 first_map.AddOrSetValue( TNumberz.THREE, crazy);
222
223 second_map.AddOrSetValue( TNumberz.SIX, looney);
224
225 insane := TThriftDictionaryImpl<Int64, IThriftDictionary<TNumberz, IInsanity>>.Create;
226
227 insane.AddOrSetValue( 1, first_map);
228 insane.AddOrSetValue( 2, second_map);
229
230 Result := insane;
231end;
232
233function TTestServer.TTestHandlerImpl.testList(
Roger Meier333bbf32012-01-08 21:51:08 +0000234 const thing: IThriftList<Integer>): IThriftList<Integer>;
Jake Farrell27274222011-11-10 20:32:44 +0000235var
236 first : Boolean;
237 elem : Integer;
238begin
239 Console.Write('testList({');
240 first := True;
241 for elem in thing do
242 begin
243 if first then
244 begin
245 first := False;
246 end else
247 begin
248 Console.Write(', ');
249 end;
250 Console.Write( IntToStr( elem));
251 end;
252 Console.WriteLine('})');
253 Result := thing;
254end;
255
256function TTestServer.TTestHandlerImpl.testMap(
Roger Meier333bbf32012-01-08 21:51:08 +0000257 const thing: IThriftDictionary<Integer, Integer>): IThriftDictionary<Integer, Integer>;
Jake Farrell27274222011-11-10 20:32:44 +0000258var
259 first : Boolean;
260 key : Integer;
261begin
262 Console.Write('testMap({');
263 first := True;
264 for key in thing.Keys do
265 begin
266 if (first) then
267 begin
268 first := false;
269 end else
270 begin
271 Console.Write(', ');
272 end;
273 Console.Write(IntToStr(key) + ' => ' + IntToStr( thing[key]));
274 end;
275 Console.WriteLine('})');
276 Result := thing;
277end;
278
279function TTestServer.TTestHandlerImpl.TestMapMap(
280 hello: Integer): IThriftDictionary<Integer, IThriftDictionary<Integer, Integer>>;
281var
282 mapmap : IThriftDictionary<Integer, IThriftDictionary<Integer, Integer>>;
283 pos : IThriftDictionary<Integer, Integer>;
284 neg : IThriftDictionary<Integer, Integer>;
285 i : Integer;
286begin
287 Console.WriteLine('testMapMap(' + IntToStr( hello) + ')');
288 mapmap := TThriftDictionaryImpl<Integer, IThriftDictionary<Integer, Integer>>.Create;
289 pos := TThriftDictionaryImpl<Integer, Integer>.Create;
290 neg := TThriftDictionaryImpl<Integer, Integer>.Create;
291
292 for i := 1 to 4 do
293 begin
294 pos.AddOrSetValue( i, i);
295 neg.AddOrSetValue( -i, -i);
296 end;
297
298 mapmap.AddOrSetValue(4, pos);
299 mapmap.AddOrSetValue( -4, neg);
300
301 Result := mapmap;
302end;
303
304function TTestServer.TTestHandlerImpl.testMulti(arg0: ShortInt; arg1: Integer;
Roger Meier333bbf32012-01-08 21:51:08 +0000305 const arg2: Int64; const arg3: IThriftDictionary<SmallInt, string>;
306 arg4: TNumberz; const arg5: Int64): IXtruct;
Jake Farrell27274222011-11-10 20:32:44 +0000307var
308 hello : IXtruct;
309begin
310 Console.WriteLine('testMulti()');
311 hello := TXtructImpl.Create;
312 hello.String_thing := 'Hello2';
313 hello.Byte_thing := arg0;
314 hello.I32_thing := arg1;
315 hello.I64_thing := arg2;
316 Result := hello;
317end;
318
Roger Meier333bbf32012-01-08 21:51:08 +0000319function TTestServer.TTestHandlerImpl.testMultiException( const arg0, arg1: string): IXtruct;
Jake Farrell27274222011-11-10 20:32:44 +0000320var
Jake Farrell27274222011-11-10 20:32:44 +0000321 x2 : TXception2;
322begin
323 Console.WriteLine('testMultiException(' + arg0 + ', ' + arg1 + ')');
324 if ( arg0 = 'Xception') then
325 begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200326 raise TXception.Create( 1001, 'This is an Xception'); // test the new rich CTOR
Jake Farrell27274222011-11-10 20:32:44 +0000327 end else
328 if ( arg0 = 'Xception2') then
329 begin
Jake Farrell343c61d2011-12-09 02:29:56 +0000330 x2 := TXception2.Create; // the old way still works too?
Jake Farrell27274222011-11-10 20:32:44 +0000331 x2.ErrorCode := 2002;
332 x2.Struct_thing := TXtructImpl.Create;
333 x2.Struct_thing.String_thing := 'This is an Xception2';
Jake Farrellac102562011-11-23 14:30:41 +0000334 x2.UpdateMessageProperty;
Jake Farrell27274222011-11-10 20:32:44 +0000335 raise x2;
336 end;
337
338 Result := TXtructImpl.Create;
339 Result.String_thing := arg1;
340end;
341
Roger Meier333bbf32012-01-08 21:51:08 +0000342function TTestServer.TTestHandlerImpl.testNest( const thing: IXtruct2): IXtruct2;
Jake Farrell27274222011-11-10 20:32:44 +0000343var
344 temp : IXtruct;
345begin
346 temp := thing.Struct_thing;
347 Console.WriteLine('testNest({' +
348 IntToStr( thing.Byte_thing) + ', {' +
349 '"' + temp.String_thing + '", ' +
350 IntToStr( temp.Byte_thing) + ', ' +
351 IntToStr( temp.I32_thing) + ', ' +
352 IntToStr( temp.I64_thing) + '}, ' +
353 IntToStr( temp.I32_thing) + '})');
354 Result := thing;
355end;
356
357procedure TTestServer.TTestHandlerImpl.testOneway(secondsToSleep: Integer);
358begin
359 Console.WriteLine('testOneway(' + IntToStr( secondsToSleep )+ '), sleeping...');
360 Sleep(secondsToSleep * 1000);
361 Console.WriteLine('testOneway finished');
362end;
363
364function TTestServer.TTestHandlerImpl.testSet(
Roger Meier333bbf32012-01-08 21:51:08 +0000365 const thing: IHashSet<Integer>):IHashSet<Integer>;
Jake Farrell27274222011-11-10 20:32:44 +0000366var
367 first : Boolean;
368 elem : Integer;
369begin
370 Console.Write('testSet({');
371 first := True;
372
373 for elem in thing do
374 begin
375 if first then
376 begin
377 first := False;
378 end else
379 begin
380 Console.Write( ', ');
381 end;
382 Console.Write( IntToStr( elem));
383 end;
384 Console.WriteLine('})');
385 Result := thing;
386end;
387
388procedure TTestServer.TTestHandlerImpl.testStop;
389begin
390 if FServer <> nil then
391 begin
392 FServer.Stop;
393 end;
394end;
395
Roger Meier333bbf32012-01-08 21:51:08 +0000396function TTestServer.TTestHandlerImpl.testString( const thing: string): string;
Jake Farrell27274222011-11-10 20:32:44 +0000397begin
398 Console.WriteLine('teststring("' + thing + '")');
399 Result := thing;
400end;
401
402function TTestServer.TTestHandlerImpl.testStringMap(
Roger Meier333bbf32012-01-08 21:51:08 +0000403 const thing: IThriftDictionary<string, string>): IThriftDictionary<string, string>;
Roger Meierbb6de7a2012-05-04 23:35:45 +0000404var
405 first : Boolean;
406 key : string;
Jake Farrell27274222011-11-10 20:32:44 +0000407begin
Roger Meierbb6de7a2012-05-04 23:35:45 +0000408 Console.Write('testStringMap({');
409 first := True;
410 for key in thing.Keys do
411 begin
412 if (first) then
413 begin
414 first := false;
415 end else
416 begin
417 Console.Write(', ');
418 end;
419 Console.Write(key + ' => ' + thing[key]);
420 end;
421 Console.WriteLine('})');
422 Result := thing;
Jake Farrell27274222011-11-10 20:32:44 +0000423end;
424
Roger Meier333bbf32012-01-08 21:51:08 +0000425function TTestServer.TTestHandlerImpl.testTypedef( const thing: Int64): Int64;
Jake Farrell27274222011-11-10 20:32:44 +0000426begin
427 Console.WriteLine('testTypedef(' + IntToStr( thing) + ')');
428 Result := thing;
429end;
430
431procedure TTestServer.TTestHandlerImpl.TestVoid;
432begin
433 Console.WriteLine('testVoid()');
434end;
435
Roger Meier333bbf32012-01-08 21:51:08 +0000436function TTestServer.TTestHandlerImpl.testStruct( const thing: IXtruct): IXtruct;
Jake Farrell27274222011-11-10 20:32:44 +0000437begin
438 Console.WriteLine('testStruct({' +
439 '"' + thing.String_thing + '", ' +
440 IntToStr( thing.Byte_thing) + ', ' +
441 IntToStr( thing.I32_thing) + ', ' +
442 IntToStr( thing.I64_thing));
443 Result := thing;
444end;
445
Roger Meier3bef8c22012-10-06 06:58:00 +0000446
Jake Farrell27274222011-11-10 20:32:44 +0000447{ TTestServer }
448
Roger Meier3bef8c22012-10-06 06:58:00 +0000449
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200450class procedure TTestServer.PrintCmdLineHelp;
451const HELPTEXT = ' [options]'#10
452 + #10
453 + 'Allowed options:'#10
454 + ' -h [ --help ] produce help message'#10
455 + ' --port arg (=9090) Port number to listen'#10
456 + ' --domain-socket arg Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)'#10
457 + ' --named-pipe arg Windows Named Pipe (e.g. MyThriftPipe)'#10
458 + ' --server-type arg (=simple) type of server, "simple", "thread-pool",'#10
459 + ' "threaded", or "nonblocking"'#10
460 + ' --transport arg (=socket) transport: buffered, framed, http, anonpipe'#10
461 + ' --protocol arg (=binary) protocol: binary, compact, json'#10
462 + ' --ssl Encrypted Transport using SSL'#10
463 + ' --processor-events processor-events'#10
464 + ' -n [ --workers ] arg (=4) Number of thread pools workers. Only valid for'#10
465 + ' thread-pool server type'#10
466 ;
467begin
468 Console.WriteLine( ChangeFileExt(ExtractFileName(ParamStr(0)),'') + HELPTEXT);
469end;
470
471class procedure TTestServer.InvalidArgs;
472begin
473 Console.WriteLine( 'Invalid args.');
474 Console.WriteLine( ChangeFileExt(ExtractFileName(ParamStr(0)),'') + ' -h for more information');
475 Abort;
476end;
477
Jens Geyer06045cf2013-03-27 20:26:25 +0200478class procedure TTestServer.LaunchAnonPipeChild( const app : string; const transport : IAnonymousPipeServerTransport);
Roger Meier3bef8c22012-10-06 06:58:00 +0000479//Launch child process and pass R/W anonymous pipe handles on cmd line.
480//This is a simple example and does not include elevation or other
481//advanced features.
482var pi : PROCESS_INFORMATION;
Jens Geyerd5436f52014-10-03 19:50:38 +0200483 si : STARTUPINFO;
484 sArg, sHandles, sCmdLine : string;
Roger Meier3bef8c22012-10-06 06:58:00 +0000485 i : Integer;
486begin
487 GetStartupInfo( si); //set startupinfo for the spawned process
488
489 // preformat handles args
490 sHandles := Format( '%d %d',
491 [ Integer(transport.ClientAnonRead),
492 Integer(transport.ClientAnonWrite)]);
493
494 // pass all settings to client
495 sCmdLine := app;
496 for i := 1 to ParamCount do begin
497 sArg := ParamStr(i);
498
499 // add anonymous handles and quote strings where appropriate
500 if sArg = '-anon'
501 then sArg := sArg +' '+ sHandles
502 else begin
503 if Pos(' ',sArg) > 0
504 then sArg := '"'+sArg+'"';
505 end;;
506
507 sCmdLine := sCmdLine +' '+ sArg;
508 end;
509
510 // spawn the child process
511 Console.WriteLine('Starting client '+sCmdLine);
512 Win32Check( CreateProcess( nil, PChar(sCmdLine), nil,nil,TRUE,0,nil,nil,si,pi));
513
514 CloseHandle( pi.hThread);
Jens Geyerd5436f52014-10-03 19:50:38 +0200515 CloseHandle( pi.hProcess);
Roger Meier3bef8c22012-10-06 06:58:00 +0000516end;
517
518
Roger Meier333bbf32012-01-08 21:51:08 +0000519class procedure TTestServer.Execute( const args: array of string);
Jake Farrell27274222011-11-10 20:32:44 +0000520var
Jake Farrell27274222011-11-10 20:32:44 +0000521 Port : Integer;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200522 ServerEvents : Boolean;
Roger Meier3bef8c22012-10-06 06:58:00 +0000523 sPipeName : string;
Jake Farrell27274222011-11-10 20:32:44 +0000524 testHandler : ITestHandler;
525 testProcessor : IProcessor;
Roger Meier3bef8c22012-10-06 06:58:00 +0000526 ServerTrans : IServerTransport;
Jake Farrell27274222011-11-10 20:32:44 +0000527 ServerEngine : IServer;
Jens Geyer06045cf2013-03-27 20:26:25 +0200528 anonymouspipe : IAnonymousPipeServerTransport;
529 namedpipe : INamedPipeServerTransport;
Jake Farrell27274222011-11-10 20:32:44 +0000530 TransportFactory : ITransportFactory;
531 ProtocolFactory : IProtocolFactory;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200532 i, numWorker : Integer;
Jake Farrell27274222011-11-10 20:32:44 +0000533 s : string;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200534 protType : TKnownProtocol;
535 servertype : TServerType;
536 endpoint : TEndpointTransport;
537 layered : TLayeredTransports;
538 UseSSL : Boolean; // include where appropriate (TLayeredTransport?)
Jens Geyer0b20cc82013-03-07 20:47:01 +0100539const
540 // pipe timeouts to be used
541 DEBUG_TIMEOUT = 30 * 1000;
Jens Geyer3e8d9272014-09-14 20:10:40 +0200542 RELEASE_TIMEOUT = DEFAULT_THRIFT_TIMEOUT; // server-side default
Jens Geyer0b20cc82013-03-07 20:47:01 +0100543 TIMEOUT = RELEASE_TIMEOUT;
Jake Farrell27274222011-11-10 20:32:44 +0000544begin
545 try
Jens Geyer01640402013-09-25 21:12:21 +0200546 ServerEvents := FALSE;
Jake Farrell27274222011-11-10 20:32:44 +0000547 protType := prot_Binary;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200548 servertype := srv_Simple;
549 endpoint := trns_Sockets;
550 layered := [];
551 UseSSL := FALSE;
Jake Farrell27274222011-11-10 20:32:44 +0000552 Port := 9090;
Roger Meier3bef8c22012-10-06 06:58:00 +0000553 sPipeName := '';
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200554 numWorker := 4;
Jake Farrell27274222011-11-10 20:32:44 +0000555
556 i := 0;
557 while ( i < Length(args) ) do begin
558 s := args[i];
559 Inc(i);
560
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200561 // Allowed options:
562 if (s = '-h') or (s = '--help') then begin
563 // -h [ --help ] produce help message
564 PrintCmdLineHelp;
565 Exit;
Roger Meier3bef8c22012-10-06 06:58:00 +0000566 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200567 else if (s = '--port') then begin
568 // --port arg (=9090) Port number to listen
569 s := args[i];
570 Inc(i);
571 Port := StrToIntDef( s, Port);
Roger Meier3bef8c22012-10-06 06:58:00 +0000572 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200573 else if (s = '--domain-socket') then begin
574 // --domain-socket arg Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)
575 raise Exception.Create('domain-socket not supported');
Roger Meier3bef8c22012-10-06 06:58:00 +0000576 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200577 else if (s = '--named-pipe') then begin
578 // --named-pipe arg Windows Named Pipe (e.g. MyThriftPipe)
579 endpoint := trns_NamedPipes;
Roger Meier3bef8c22012-10-06 06:58:00 +0000580 sPipeName := args[i]; // -pipe <name>
581 Inc( i );
582 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200583 else if (s = '--server-type') then begin
584 // --server-type arg (=simple) type of server,
585 // arg = "simple", "thread-pool", "threaded", or "nonblocking"
Jake Farrell27274222011-11-10 20:32:44 +0000586 s := args[i];
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200587 Inc(i);
588
589 if s = 'simple' then servertype := srv_Simple
590 else if s = 'thread-pool' then servertype := srv_Threadpool
591 else if s = 'threaded' then servertype := srv_Threaded
592 else if s = 'nonblocking' then servertype := srv_Nonblocking
593 else InvalidArgs;
Jens Geyer01640402013-09-25 21:12:21 +0200594 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200595 else if (s = '--transport') then begin
596 // --transport arg (=buffered) transport: buffered, framed, http
597 s := args[i];
598 Inc(i);
599
600 if s = 'buffered' then Include( layered, trns_Buffered)
601 else if s = 'framed' then Include( layered, trns_Framed)
602 else if s = 'http' then endpoint := trns_Http
603 else if s = 'anonpipe' then endpoint := trns_AnonPipes
604 else InvalidArgs;
605 end
606 else if (s = '--protocol') then begin
607 // --protocol arg (=binary) protocol: binary, compact, json
608 s := args[i];
609 Inc(i);
610
611 if s = 'binary' then protType := prot_Binary
612 else if s = 'compact' then protType := prot_Compact
613 else if s = 'json' then protType := prot_JSON
614 else InvalidArgs;
615 end
616 else if (s = '--ssl') then begin
617 // --ssl Encrypted Transport using SSL
618 UseSSL := TRUE;
619 end
620 else if (s = '--processor-events') then begin
621 // --processor-events processor-events
622 ServerEvents := TRUE;
623 end
624 else if (s = '-n') or (s = '--workers') then begin
625 // -n [ --workers ] arg (=4) Number of thread pools workers.
626 // Only valid for thread-pool server type
627 s := args[i];
628 numWorker := StrToIntDef(s,0);
629 if numWorker > 0
630 then Inc(i)
631 else numWorker := 4;
Jens Geyer01640402013-09-25 21:12:21 +0200632 end
633 else begin
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200634 InvalidArgs;
635 end;
Jake Farrell27274222011-11-10 20:32:44 +0000636 end;
637
Roger Meier3bef8c22012-10-06 06:58:00 +0000638
639 Console.WriteLine('Server configuration: ');
640
Jake Farrell27274222011-11-10 20:32:44 +0000641 // create protocol factory, default to BinaryProtocol
642 case protType of
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200643 prot_Binary : ProtocolFactory := TBinaryProtocolImpl.TFactory.Create( BINARY_STRICT_READ, BINARY_STRICT_WRITE);
644 prot_JSON : ProtocolFactory := TJSONProtocolImpl.TFactory.Create;
645 prot_Compact : raise Exception.Create('Compact protocol not implemented');
Jake Farrell27274222011-11-10 20:32:44 +0000646 else
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200647 raise Exception.Create('Unhandled protocol');
Jake Farrell27274222011-11-10 20:32:44 +0000648 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000649 ASSERT( ProtocolFactory <> nil);
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200650 Console.WriteLine('- '+THRIFT_PROTOCOLS[protType]+' protocol');
Jake Farrell27274222011-11-10 20:32:44 +0000651
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200652 case endpoint of
Jake Farrell27274222011-11-10 20:32:44 +0000653
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200654 trns_Sockets : begin
655 Console.WriteLine('- sockets (port '+IntToStr(port)+')');
656 if (trns_Buffered in layered) then Console.WriteLine('- buffered');
657 servertrans := TServerSocketImpl.Create( Port, 0, (trns_Buffered in layered));
658 end;
659
660 trns_Http : begin
661 raise Exception.Create('HTTP server transport not implemented');
662 end;
663
664 trns_NamedPipes : begin
665 Console.WriteLine('- named pipe ('+sPipeName+')');
666 namedpipe := TNamedPipeServerTransportImpl.Create( sPipeName, 4096, PIPE_UNLIMITED_INSTANCES, TIMEOUT);
667 servertrans := namedpipe;
668 end;
669
670 trns_AnonPipes : begin
671 Console.WriteLine('- anonymous pipes');
672 anonymouspipe := TAnonymousPipeServerTransportImpl.Create;
673 servertrans := anonymouspipe;
674 end
675
676 else
677 raise Exception.Create('Unhandled endpoint transport');
Roger Meier3bef8c22012-10-06 06:58:00 +0000678 end;
679 ASSERT( servertrans <> nil);
680
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200681 if UseSSL then begin
682 raise Exception.Create('SSL not implemented');
683 end;
684
685 if (trns_Framed in layered) then begin
Roger Meier3bef8c22012-10-06 06:58:00 +0000686 Console.WriteLine('- framed transport');
687 TransportFactory := TFramedTransportImpl.TFactory.Create
688 end
689 else begin
690 TransportFactory := TTransportFactoryImpl.Create;
691 end;
692 ASSERT( TransportFactory <> nil);
693
694 testHandler := TTestHandlerImpl.Create;
Jake Farrell27274222011-11-10 20:32:44 +0000695 testProcessor := TThriftTest.TProcessorImpl.Create( testHandler );
Jake Farrell27274222011-11-10 20:32:44 +0000696
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200697 case servertype of
698 srv_Simple : begin
699 ServerEngine := TSimpleServer.Create( testProcessor, ServerTrans, TransportFactory, ProtocolFactory);
700 end;
701
702 srv_Nonblocking : begin
703 raise Exception.Create(SERVER_TYPES[servertype]+' server not implemented');
704 end;
705
706 srv_Threadpool,
707 srv_Threaded: begin
708 if numWorker > 1 then {use here};
709 raise Exception.Create(SERVER_TYPES[servertype]+' server not implemented');
710 end;
711
712 else
713 raise Exception.Create('Unhandled server type');
714 end;
715 ASSERT( ServerEngine <> nil);
Jake Farrell27274222011-11-10 20:32:44 +0000716
717 testHandler.SetServer( ServerEngine);
718
Jens Geyer01640402013-09-25 21:12:21 +0200719 // test events?
720 if ServerEvents then begin
721 Console.WriteLine('- server events test enabled');
722 ServerEngine.ServerEvents := TServerEventsImpl.Create;
723 end;
724
Roger Meier3bef8c22012-10-06 06:58:00 +0000725 // start the client now when we have the anon handles, but before the server starts
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200726 if endpoint = trns_AnonPipes
Roger Meier79655fb2012-10-20 20:59:41 +0000727 then LaunchAnonPipeChild( ExtractFilePath(ParamStr(0))+'client.exe', anonymouspipe);
Jake Farrell27274222011-11-10 20:32:44 +0000728
Jens Geyer06045cf2013-03-27 20:26:25 +0200729 // install Ctrl+C handler before the server starts
730 g_Handler := testHandler;
731 SetConsoleCtrlHandler( @MyConsoleEventHandler, TRUE);
Roger Meier3bef8c22012-10-06 06:58:00 +0000732
733 Console.WriteLine('');
Jens Geyer06045cf2013-03-27 20:26:25 +0200734 repeat
735 Console.WriteLine('Starting the server ...');
736 serverEngine.Serve;
737 until {$IFDEF RunEndless} FALSE {$ELSE} TRUE {$ENDIF};
738
Jake Farrell27274222011-11-10 20:32:44 +0000739 testHandler.SetServer( nil);
Jens Geyer06045cf2013-03-27 20:26:25 +0200740 g_Handler := nil;
Jake Farrell27274222011-11-10 20:32:44 +0000741
742 except
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200743 on E: EAbort do raise;
744 on E: Exception do begin
745 Console.WriteLine( E.Message + #10 + E.StackTrace );
Jake Farrell27274222011-11-10 20:32:44 +0000746 end;
747 end;
748 Console.WriteLine( 'done.');
749end;
750
Jens Geyer06045cf2013-03-27 20:26:25 +0200751
Jake Farrell27274222011-11-10 20:32:44 +0000752end.