blob: 4f599eaae86727e31f8d9a8fc5149eb4973464f0 [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,
Jens Geyerf0e63312015-03-01 18:47:49 +010037 Thrift.Protocol.Compact,
Jake Farrell27274222011-11-10 20:32:44 +000038 Thrift.Collections,
39 Thrift.Utils,
40 Thrift.Test,
41 Thrift,
42 TestConstants,
Jens Geyer01640402013-09-25 21:12:21 +020043 TestServerEvents,
Jake Farrell27274222011-11-10 20:32:44 +000044 Contnrs;
45
46type
47 TTestServer = class
48 public
49 type
50
51 ITestHandler = interface( TThriftTest.Iface )
Roger Meier333bbf32012-01-08 21:51:08 +000052 procedure SetServer( const AServer : IServer );
Jens Geyer06045cf2013-03-27 20:26:25 +020053 procedure TestStop;
Jake Farrell27274222011-11-10 20:32:44 +000054 end;
55
56 TTestHandlerImpl = class( TInterfacedObject, ITestHandler )
57 private
58 FServer : IServer;
59 protected
60 procedure testVoid();
Roger Meier333bbf32012-01-08 21:51:08 +000061 function testString(const thing: string): string;
Jake Farrell7ae13e12011-10-18 14:35:26 +000062 function testByte(thing: ShortInt): ShortInt;
63 function testI32(thing: Integer): Integer;
Roger Meier333bbf32012-01-08 21:51:08 +000064 function testI64(const thing: Int64): Int64;
65 function testDouble(const thing: Double): Double;
Jens Geyerfd1b3582014-12-13 23:42:58 +010066 function testBinary(const thing: TBytes): TBytes;
Roger Meier333bbf32012-01-08 21:51:08 +000067 function testStruct(const thing: IXtruct): IXtruct;
68 function testNest(const thing: IXtruct2): IXtruct2;
69 function testMap(const thing: IThriftDictionary<Integer, Integer>): IThriftDictionary<Integer, Integer>;
70 function testStringMap(const thing: IThriftDictionary<string, string>): IThriftDictionary<string, string>;
71 function testSet(const thing: IHashSet<Integer>): IHashSet<Integer>;
72 function testList(const thing: IThriftList<Integer>): IThriftList<Integer>;
Jake Farrell7ae13e12011-10-18 14:35:26 +000073 function testEnum(thing: TNumberz): TNumberz;
Roger Meier333bbf32012-01-08 21:51:08 +000074 function testTypedef(const thing: Int64): Int64;
Jake Farrell7ae13e12011-10-18 14:35:26 +000075 function testMapMap(hello: Integer): IThriftDictionary<Integer, IThriftDictionary<Integer, Integer>>;
Roger Meier333bbf32012-01-08 21:51:08 +000076 function testInsanity(const argument: IInsanity): IThriftDictionary<Int64, IThriftDictionary<TNumberz, IInsanity>>;
77 function testMulti(arg0: ShortInt; arg1: Integer; const arg2: Int64; const arg3: IThriftDictionary<SmallInt, string>; arg4: TNumberz; const arg5: Int64): IXtruct;
78 procedure testException(const arg: string);
79 function testMultiException(const arg0: string; const arg1: string): IXtruct;
Jake Farrell7ae13e12011-10-18 14:35:26 +000080 procedure testOneway(secondsToSleep: Integer);
Jake Farrell27274222011-11-10 20:32:44 +000081
Jens Geyer06045cf2013-03-27 20:26:25 +020082 procedure TestStop;
Roger Meier333bbf32012-01-08 21:51:08 +000083 procedure SetServer( const AServer : IServer );
Jake Farrell27274222011-11-10 20:32:44 +000084 end;
85
Jens Geyerf8a1b7a2014-09-24 00:26:46 +020086 class procedure PrintCmdLineHelp;
87 class procedure InvalidArgs;
88
Jens Geyer06045cf2013-03-27 20:26:25 +020089 class procedure LaunchAnonPipeChild( const app : string; const transport : IAnonymousPipeServerTransport);
Roger Meier333bbf32012-01-08 21:51:08 +000090 class procedure Execute( const args: array of string);
Jake Farrell27274222011-11-10 20:32:44 +000091 end;
92
93implementation
94
Jens Geyer06045cf2013-03-27 20:26:25 +020095
96var g_Handler : TTestServer.ITestHandler = nil;
97
98
99function MyConsoleEventHandler( dwCtrlType : DWORD) : BOOL; stdcall;
100// Note that this Handler procedure is called from another thread
101var handler : TTestServer.ITestHandler;
102begin
103 result := TRUE;
104 try
105 case dwCtrlType of
106 CTRL_C_EVENT : Console.WriteLine( 'Ctrl+C pressed');
107 CTRL_BREAK_EVENT : Console.WriteLine( 'Ctrl+Break pressed');
108 CTRL_CLOSE_EVENT : Console.WriteLine( 'Received CloseTask signal');
109 CTRL_LOGOFF_EVENT : Console.WriteLine( 'Received LogOff signal');
110 CTRL_SHUTDOWN_EVENT : Console.WriteLine( 'Received Shutdown signal');
111 else
112 Console.WriteLine( 'Received console event #'+IntToStr(Integer(dwCtrlType)));
113 end;
114
115 handler := g_Handler;
116 if handler <> nil then handler.TestStop;
117
118 except
119 // catch all
120 end;
121end;
122
123
Jake Farrell27274222011-11-10 20:32:44 +0000124{ TTestServer.TTestHandlerImpl }
125
Roger Meier333bbf32012-01-08 21:51:08 +0000126procedure TTestServer.TTestHandlerImpl.SetServer( const AServer: IServer);
Jake Farrell27274222011-11-10 20:32:44 +0000127begin
128 FServer := AServer;
129end;
130
131function TTestServer.TTestHandlerImpl.testByte(thing: ShortInt): ShortInt;
132begin
133 Console.WriteLine('testByte("' + IntToStr( thing) + '")');
134 Result := thing;
135end;
136
Roger Meier333bbf32012-01-08 21:51:08 +0000137function TTestServer.TTestHandlerImpl.testDouble( const thing: Double): Double;
Jake Farrell27274222011-11-10 20:32:44 +0000138begin
139 Console.WriteLine('testDouble("' + FloatToStr( thing ) + '")');
140 Result := thing;
141end;
142
Jens Geyerfd1b3582014-12-13 23:42:58 +0100143function TTestServer.TTestHandlerImpl.testBinary(const thing: TBytes): TBytes;
144begin
145 Console.WriteLine('testBinary("' + BytesToHex( thing ) + '")');
146 Result := thing;
147end;
148
Jake Farrell27274222011-11-10 20:32:44 +0000149function TTestServer.TTestHandlerImpl.testEnum(thing: TNumberz): TNumberz;
150begin
151 Console.WriteLine('testEnum(' + IntToStr( Integer( thing)) + ')');
152 Result := thing;
153end;
154
Roger Meier333bbf32012-01-08 21:51:08 +0000155procedure TTestServer.TTestHandlerImpl.testException(const arg: string);
Jake Farrell27274222011-11-10 20:32:44 +0000156begin
157 Console.WriteLine('testException(' + arg + ')');
158 if ( arg = 'Xception') then
159 begin
Roger Meierbb6de7a2012-05-04 23:35:45 +0000160 raise TXception.Create( 1001, arg);
Jake Farrell27274222011-11-10 20:32:44 +0000161 end;
Roger Meierbb6de7a2012-05-04 23:35:45 +0000162
163 if (arg = 'TException') then
164 begin
165 raise TException.Create('');
166 end;
167
168 // else do not throw anything
Jake Farrell27274222011-11-10 20:32:44 +0000169end;
170
171function TTestServer.TTestHandlerImpl.testI32(thing: Integer): Integer;
172begin
173 Console.WriteLine('testI32("' + IntToStr( thing) + '")');
174 Result := thing;
175end;
176
Roger Meier333bbf32012-01-08 21:51:08 +0000177function TTestServer.TTestHandlerImpl.testI64( const thing: Int64): Int64;
Jake Farrell27274222011-11-10 20:32:44 +0000178begin
179 Console.WriteLine('testI64("' + IntToStr( thing) + '")');
180 Result := thing;
181end;
182
183function TTestServer.TTestHandlerImpl.testInsanity(
Roger Meier333bbf32012-01-08 21:51:08 +0000184 const argument: IInsanity): IThriftDictionary<Int64, IThriftDictionary<TNumberz, IInsanity>>;
Jake Farrell27274222011-11-10 20:32:44 +0000185var
186 hello, goodbye : IXtruct;
187 crazy : IInsanity;
188 looney : IInsanity;
189 first_map : IThriftDictionary<TNumberz, IInsanity>;
190 second_map : IThriftDictionary<TNumberz, IInsanity>;
191 insane : IThriftDictionary<Int64, IThriftDictionary<TNumberz, IInsanity>>;
192
193begin
194
195 Console.WriteLine('testInsanity()');
196 hello := TXtructImpl.Create;
Roger Meierbb6de7a2012-05-04 23:35:45 +0000197 hello.String_thing := 'Hello2';
Jake Farrell27274222011-11-10 20:32:44 +0000198 hello.Byte_thing := 2;
199 hello.I32_thing := 2;
200 hello.I64_thing := 2;
201
202 goodbye := TXtructImpl.Create;
203 goodbye.String_thing := 'Goodbye4';
204 goodbye.Byte_thing := 4;
205 goodbye.I32_thing := 4;
206 goodbye.I64_thing := 4;
207
208 crazy := TInsanityImpl.Create;
209 crazy.UserMap := TThriftDictionaryImpl<TNumberz, Int64>.Create;
210 crazy.UserMap.AddOrSetValue( TNumberz.EIGHT, 8);
211 crazy.Xtructs := TThriftListImpl<IXtruct>.Create;
212 crazy.Xtructs.Add(goodbye);
213
214 looney := TInsanityImpl.Create;
215 crazy.UserMap.AddOrSetValue( TNumberz.FIVE, 5);
216 crazy.Xtructs.Add(hello);
217
218 first_map := TThriftDictionaryImpl<TNumberz, IInsanity>.Create;
219 second_map := TThriftDictionaryImpl<TNumberz, IInsanity>.Create;
220
Roger Meierbb6de7a2012-05-04 23:35:45 +0000221 first_map.AddOrSetValue( TNumberz.TWO, crazy);
Jake Farrell27274222011-11-10 20:32:44 +0000222 first_map.AddOrSetValue( TNumberz.THREE, crazy);
223
224 second_map.AddOrSetValue( TNumberz.SIX, looney);
225
226 insane := TThriftDictionaryImpl<Int64, IThriftDictionary<TNumberz, IInsanity>>.Create;
227
228 insane.AddOrSetValue( 1, first_map);
229 insane.AddOrSetValue( 2, second_map);
230
231 Result := insane;
232end;
233
234function TTestServer.TTestHandlerImpl.testList(
Roger Meier333bbf32012-01-08 21:51:08 +0000235 const thing: IThriftList<Integer>): IThriftList<Integer>;
Jake Farrell27274222011-11-10 20:32:44 +0000236var
237 first : Boolean;
238 elem : Integer;
239begin
240 Console.Write('testList({');
241 first := True;
242 for elem in thing do
243 begin
244 if first then
245 begin
246 first := False;
247 end else
248 begin
249 Console.Write(', ');
250 end;
251 Console.Write( IntToStr( elem));
252 end;
253 Console.WriteLine('})');
254 Result := thing;
255end;
256
257function TTestServer.TTestHandlerImpl.testMap(
Roger Meier333bbf32012-01-08 21:51:08 +0000258 const thing: IThriftDictionary<Integer, Integer>): IThriftDictionary<Integer, Integer>;
Jake Farrell27274222011-11-10 20:32:44 +0000259var
260 first : Boolean;
261 key : Integer;
262begin
263 Console.Write('testMap({');
264 first := True;
265 for key in thing.Keys do
266 begin
267 if (first) then
268 begin
269 first := false;
270 end else
271 begin
272 Console.Write(', ');
273 end;
274 Console.Write(IntToStr(key) + ' => ' + IntToStr( thing[key]));
275 end;
276 Console.WriteLine('})');
277 Result := thing;
278end;
279
280function TTestServer.TTestHandlerImpl.TestMapMap(
281 hello: Integer): IThriftDictionary<Integer, IThriftDictionary<Integer, Integer>>;
282var
283 mapmap : IThriftDictionary<Integer, IThriftDictionary<Integer, Integer>>;
284 pos : IThriftDictionary<Integer, Integer>;
285 neg : IThriftDictionary<Integer, Integer>;
286 i : Integer;
287begin
288 Console.WriteLine('testMapMap(' + IntToStr( hello) + ')');
289 mapmap := TThriftDictionaryImpl<Integer, IThriftDictionary<Integer, Integer>>.Create;
290 pos := TThriftDictionaryImpl<Integer, Integer>.Create;
291 neg := TThriftDictionaryImpl<Integer, Integer>.Create;
292
293 for i := 1 to 4 do
294 begin
295 pos.AddOrSetValue( i, i);
296 neg.AddOrSetValue( -i, -i);
297 end;
298
299 mapmap.AddOrSetValue(4, pos);
300 mapmap.AddOrSetValue( -4, neg);
301
302 Result := mapmap;
303end;
304
305function TTestServer.TTestHandlerImpl.testMulti(arg0: ShortInt; arg1: Integer;
Roger Meier333bbf32012-01-08 21:51:08 +0000306 const arg2: Int64; const arg3: IThriftDictionary<SmallInt, string>;
307 arg4: TNumberz; const arg5: Int64): IXtruct;
Jake Farrell27274222011-11-10 20:32:44 +0000308var
309 hello : IXtruct;
310begin
311 Console.WriteLine('testMulti()');
312 hello := TXtructImpl.Create;
313 hello.String_thing := 'Hello2';
314 hello.Byte_thing := arg0;
315 hello.I32_thing := arg1;
316 hello.I64_thing := arg2;
317 Result := hello;
318end;
319
Roger Meier333bbf32012-01-08 21:51:08 +0000320function TTestServer.TTestHandlerImpl.testMultiException( const arg0, arg1: string): IXtruct;
Jake Farrell27274222011-11-10 20:32:44 +0000321var
Jake Farrell27274222011-11-10 20:32:44 +0000322 x2 : TXception2;
323begin
324 Console.WriteLine('testMultiException(' + arg0 + ', ' + arg1 + ')');
325 if ( arg0 = 'Xception') then
326 begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200327 raise TXception.Create( 1001, 'This is an Xception'); // test the new rich CTOR
Jake Farrell27274222011-11-10 20:32:44 +0000328 end else
329 if ( arg0 = 'Xception2') then
330 begin
Jake Farrell343c61d2011-12-09 02:29:56 +0000331 x2 := TXception2.Create; // the old way still works too?
Jake Farrell27274222011-11-10 20:32:44 +0000332 x2.ErrorCode := 2002;
333 x2.Struct_thing := TXtructImpl.Create;
334 x2.Struct_thing.String_thing := 'This is an Xception2';
Jake Farrellac102562011-11-23 14:30:41 +0000335 x2.UpdateMessageProperty;
Jake Farrell27274222011-11-10 20:32:44 +0000336 raise x2;
337 end;
338
339 Result := TXtructImpl.Create;
340 Result.String_thing := arg1;
341end;
342
Roger Meier333bbf32012-01-08 21:51:08 +0000343function TTestServer.TTestHandlerImpl.testNest( const thing: IXtruct2): IXtruct2;
Jake Farrell27274222011-11-10 20:32:44 +0000344var
345 temp : IXtruct;
346begin
347 temp := thing.Struct_thing;
348 Console.WriteLine('testNest({' +
349 IntToStr( thing.Byte_thing) + ', {' +
350 '"' + temp.String_thing + '", ' +
351 IntToStr( temp.Byte_thing) + ', ' +
352 IntToStr( temp.I32_thing) + ', ' +
353 IntToStr( temp.I64_thing) + '}, ' +
354 IntToStr( temp.I32_thing) + '})');
355 Result := thing;
356end;
357
358procedure TTestServer.TTestHandlerImpl.testOneway(secondsToSleep: Integer);
359begin
360 Console.WriteLine('testOneway(' + IntToStr( secondsToSleep )+ '), sleeping...');
361 Sleep(secondsToSleep * 1000);
362 Console.WriteLine('testOneway finished');
363end;
364
365function TTestServer.TTestHandlerImpl.testSet(
Roger Meier333bbf32012-01-08 21:51:08 +0000366 const thing: IHashSet<Integer>):IHashSet<Integer>;
Jake Farrell27274222011-11-10 20:32:44 +0000367var
368 first : Boolean;
369 elem : Integer;
370begin
371 Console.Write('testSet({');
372 first := True;
373
374 for elem in thing do
375 begin
376 if first then
377 begin
378 first := False;
379 end else
380 begin
381 Console.Write( ', ');
382 end;
383 Console.Write( IntToStr( elem));
384 end;
385 Console.WriteLine('})');
386 Result := thing;
387end;
388
389procedure TTestServer.TTestHandlerImpl.testStop;
390begin
391 if FServer <> nil then
392 begin
393 FServer.Stop;
394 end;
395end;
396
Roger Meier333bbf32012-01-08 21:51:08 +0000397function TTestServer.TTestHandlerImpl.testString( const thing: string): string;
Jake Farrell27274222011-11-10 20:32:44 +0000398begin
399 Console.WriteLine('teststring("' + thing + '")');
400 Result := thing;
401end;
402
403function TTestServer.TTestHandlerImpl.testStringMap(
Roger Meier333bbf32012-01-08 21:51:08 +0000404 const thing: IThriftDictionary<string, string>): IThriftDictionary<string, string>;
Roger Meierbb6de7a2012-05-04 23:35:45 +0000405var
406 first : Boolean;
407 key : string;
Jake Farrell27274222011-11-10 20:32:44 +0000408begin
Roger Meierbb6de7a2012-05-04 23:35:45 +0000409 Console.Write('testStringMap({');
410 first := True;
411 for key in thing.Keys do
412 begin
413 if (first) then
414 begin
415 first := false;
416 end else
417 begin
418 Console.Write(', ');
419 end;
420 Console.Write(key + ' => ' + thing[key]);
421 end;
422 Console.WriteLine('})');
423 Result := thing;
Jake Farrell27274222011-11-10 20:32:44 +0000424end;
425
Roger Meier333bbf32012-01-08 21:51:08 +0000426function TTestServer.TTestHandlerImpl.testTypedef( const thing: Int64): Int64;
Jake Farrell27274222011-11-10 20:32:44 +0000427begin
428 Console.WriteLine('testTypedef(' + IntToStr( thing) + ')');
429 Result := thing;
430end;
431
432procedure TTestServer.TTestHandlerImpl.TestVoid;
433begin
434 Console.WriteLine('testVoid()');
435end;
436
Roger Meier333bbf32012-01-08 21:51:08 +0000437function TTestServer.TTestHandlerImpl.testStruct( const thing: IXtruct): IXtruct;
Jake Farrell27274222011-11-10 20:32:44 +0000438begin
439 Console.WriteLine('testStruct({' +
440 '"' + thing.String_thing + '", ' +
441 IntToStr( thing.Byte_thing) + ', ' +
442 IntToStr( thing.I32_thing) + ', ' +
443 IntToStr( thing.I64_thing));
444 Result := thing;
445end;
446
Roger Meier3bef8c22012-10-06 06:58:00 +0000447
Jake Farrell27274222011-11-10 20:32:44 +0000448{ TTestServer }
449
Roger Meier3bef8c22012-10-06 06:58:00 +0000450
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200451class procedure TTestServer.PrintCmdLineHelp;
452const HELPTEXT = ' [options]'#10
453 + #10
454 + 'Allowed options:'#10
455 + ' -h [ --help ] produce help message'#10
456 + ' --port arg (=9090) Port number to listen'#10
457 + ' --domain-socket arg Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)'#10
458 + ' --named-pipe arg Windows Named Pipe (e.g. MyThriftPipe)'#10
459 + ' --server-type arg (=simple) type of server, "simple", "thread-pool",'#10
460 + ' "threaded", or "nonblocking"'#10
461 + ' --transport arg (=socket) transport: buffered, framed, http, anonpipe'#10
462 + ' --protocol arg (=binary) protocol: binary, compact, json'#10
463 + ' --ssl Encrypted Transport using SSL'#10
464 + ' --processor-events processor-events'#10
465 + ' -n [ --workers ] arg (=4) Number of thread pools workers. Only valid for'#10
466 + ' thread-pool server type'#10
467 ;
468begin
469 Console.WriteLine( ChangeFileExt(ExtractFileName(ParamStr(0)),'') + HELPTEXT);
470end;
471
472class procedure TTestServer.InvalidArgs;
473begin
474 Console.WriteLine( 'Invalid args.');
475 Console.WriteLine( ChangeFileExt(ExtractFileName(ParamStr(0)),'') + ' -h for more information');
476 Abort;
477end;
478
Jens Geyer06045cf2013-03-27 20:26:25 +0200479class procedure TTestServer.LaunchAnonPipeChild( const app : string; const transport : IAnonymousPipeServerTransport);
Roger Meier3bef8c22012-10-06 06:58:00 +0000480//Launch child process and pass R/W anonymous pipe handles on cmd line.
481//This is a simple example and does not include elevation or other
482//advanced features.
483var pi : PROCESS_INFORMATION;
Jens Geyerd5436f52014-10-03 19:50:38 +0200484 si : STARTUPINFO;
485 sArg, sHandles, sCmdLine : string;
Roger Meier3bef8c22012-10-06 06:58:00 +0000486 i : Integer;
487begin
488 GetStartupInfo( si); //set startupinfo for the spawned process
489
490 // preformat handles args
491 sHandles := Format( '%d %d',
492 [ Integer(transport.ClientAnonRead),
493 Integer(transport.ClientAnonWrite)]);
494
495 // pass all settings to client
496 sCmdLine := app;
497 for i := 1 to ParamCount do begin
498 sArg := ParamStr(i);
499
500 // add anonymous handles and quote strings where appropriate
501 if sArg = '-anon'
502 then sArg := sArg +' '+ sHandles
503 else begin
504 if Pos(' ',sArg) > 0
505 then sArg := '"'+sArg+'"';
506 end;;
507
508 sCmdLine := sCmdLine +' '+ sArg;
509 end;
510
511 // spawn the child process
512 Console.WriteLine('Starting client '+sCmdLine);
513 Win32Check( CreateProcess( nil, PChar(sCmdLine), nil,nil,TRUE,0,nil,nil,si,pi));
514
515 CloseHandle( pi.hThread);
Jens Geyerd5436f52014-10-03 19:50:38 +0200516 CloseHandle( pi.hProcess);
Roger Meier3bef8c22012-10-06 06:58:00 +0000517end;
518
519
Roger Meier333bbf32012-01-08 21:51:08 +0000520class procedure TTestServer.Execute( const args: array of string);
Jake Farrell27274222011-11-10 20:32:44 +0000521var
Jake Farrell27274222011-11-10 20:32:44 +0000522 Port : Integer;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200523 ServerEvents : Boolean;
Roger Meier3bef8c22012-10-06 06:58:00 +0000524 sPipeName : string;
Jake Farrell27274222011-11-10 20:32:44 +0000525 testHandler : ITestHandler;
526 testProcessor : IProcessor;
Roger Meier3bef8c22012-10-06 06:58:00 +0000527 ServerTrans : IServerTransport;
Jake Farrell27274222011-11-10 20:32:44 +0000528 ServerEngine : IServer;
Jens Geyer06045cf2013-03-27 20:26:25 +0200529 anonymouspipe : IAnonymousPipeServerTransport;
530 namedpipe : INamedPipeServerTransport;
Jake Farrell27274222011-11-10 20:32:44 +0000531 TransportFactory : ITransportFactory;
532 ProtocolFactory : IProtocolFactory;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200533 i, numWorker : Integer;
Jake Farrell27274222011-11-10 20:32:44 +0000534 s : string;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200535 protType : TKnownProtocol;
536 servertype : TServerType;
537 endpoint : TEndpointTransport;
538 layered : TLayeredTransports;
539 UseSSL : Boolean; // include where appropriate (TLayeredTransport?)
Jake Farrell27274222011-11-10 20:32:44 +0000540begin
541 try
Jens Geyer01640402013-09-25 21:12:21 +0200542 ServerEvents := FALSE;
Jake Farrell27274222011-11-10 20:32:44 +0000543 protType := prot_Binary;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200544 servertype := srv_Simple;
545 endpoint := trns_Sockets;
546 layered := [];
547 UseSSL := FALSE;
Jake Farrell27274222011-11-10 20:32:44 +0000548 Port := 9090;
Roger Meier3bef8c22012-10-06 06:58:00 +0000549 sPipeName := '';
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200550 numWorker := 4;
Jake Farrell27274222011-11-10 20:32:44 +0000551
552 i := 0;
553 while ( i < Length(args) ) do begin
554 s := args[i];
555 Inc(i);
556
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200557 // Allowed options:
558 if (s = '-h') or (s = '--help') then begin
559 // -h [ --help ] produce help message
560 PrintCmdLineHelp;
561 Exit;
Roger Meier3bef8c22012-10-06 06:58:00 +0000562 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200563 else if (s = '--port') then begin
564 // --port arg (=9090) Port number to listen
565 s := args[i];
566 Inc(i);
567 Port := StrToIntDef( s, Port);
Roger Meier3bef8c22012-10-06 06:58:00 +0000568 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200569 else if (s = '--domain-socket') then begin
570 // --domain-socket arg Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)
571 raise Exception.Create('domain-socket not supported');
Roger Meier3bef8c22012-10-06 06:58:00 +0000572 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200573 else if (s = '--named-pipe') then begin
574 // --named-pipe arg Windows Named Pipe (e.g. MyThriftPipe)
575 endpoint := trns_NamedPipes;
Roger Meier3bef8c22012-10-06 06:58:00 +0000576 sPipeName := args[i]; // -pipe <name>
577 Inc( i );
578 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200579 else if (s = '--server-type') then begin
580 // --server-type arg (=simple) type of server,
581 // arg = "simple", "thread-pool", "threaded", or "nonblocking"
Jake Farrell27274222011-11-10 20:32:44 +0000582 s := args[i];
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200583 Inc(i);
584
585 if s = 'simple' then servertype := srv_Simple
586 else if s = 'thread-pool' then servertype := srv_Threadpool
587 else if s = 'threaded' then servertype := srv_Threaded
588 else if s = 'nonblocking' then servertype := srv_Nonblocking
589 else InvalidArgs;
Jens Geyer01640402013-09-25 21:12:21 +0200590 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200591 else if (s = '--transport') then begin
592 // --transport arg (=buffered) transport: buffered, framed, http
593 s := args[i];
594 Inc(i);
595
596 if s = 'buffered' then Include( layered, trns_Buffered)
597 else if s = 'framed' then Include( layered, trns_Framed)
598 else if s = 'http' then endpoint := trns_Http
599 else if s = 'anonpipe' then endpoint := trns_AnonPipes
600 else InvalidArgs;
601 end
602 else if (s = '--protocol') then begin
603 // --protocol arg (=binary) protocol: binary, compact, json
604 s := args[i];
605 Inc(i);
606
607 if s = 'binary' then protType := prot_Binary
608 else if s = 'compact' then protType := prot_Compact
609 else if s = 'json' then protType := prot_JSON
610 else InvalidArgs;
611 end
612 else if (s = '--ssl') then begin
613 // --ssl Encrypted Transport using SSL
614 UseSSL := TRUE;
615 end
616 else if (s = '--processor-events') then begin
617 // --processor-events processor-events
618 ServerEvents := TRUE;
619 end
620 else if (s = '-n') or (s = '--workers') then begin
621 // -n [ --workers ] arg (=4) Number of thread pools workers.
622 // Only valid for thread-pool server type
623 s := args[i];
624 numWorker := StrToIntDef(s,0);
625 if numWorker > 0
626 then Inc(i)
627 else numWorker := 4;
Jens Geyer01640402013-09-25 21:12:21 +0200628 end
629 else begin
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200630 InvalidArgs;
631 end;
Jake Farrell27274222011-11-10 20:32:44 +0000632 end;
633
Roger Meier3bef8c22012-10-06 06:58:00 +0000634
635 Console.WriteLine('Server configuration: ');
636
Jake Farrell27274222011-11-10 20:32:44 +0000637 // create protocol factory, default to BinaryProtocol
638 case protType of
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200639 prot_Binary : ProtocolFactory := TBinaryProtocolImpl.TFactory.Create( BINARY_STRICT_READ, BINARY_STRICT_WRITE);
640 prot_JSON : ProtocolFactory := TJSONProtocolImpl.TFactory.Create;
Jens Geyerf0e63312015-03-01 18:47:49 +0100641 prot_Compact : ProtocolFactory := TCompactProtocolImpl.TFactory.Create;
Jake Farrell27274222011-11-10 20:32:44 +0000642 else
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200643 raise Exception.Create('Unhandled protocol');
Jake Farrell27274222011-11-10 20:32:44 +0000644 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000645 ASSERT( ProtocolFactory <> nil);
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200646 Console.WriteLine('- '+THRIFT_PROTOCOLS[protType]+' protocol');
Jake Farrell27274222011-11-10 20:32:44 +0000647
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200648 case endpoint of
Jake Farrell27274222011-11-10 20:32:44 +0000649
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200650 trns_Sockets : begin
651 Console.WriteLine('- sockets (port '+IntToStr(port)+')');
652 if (trns_Buffered in layered) then Console.WriteLine('- buffered');
653 servertrans := TServerSocketImpl.Create( Port, 0, (trns_Buffered in layered));
654 end;
655
656 trns_Http : begin
657 raise Exception.Create('HTTP server transport not implemented');
658 end;
659
660 trns_NamedPipes : begin
661 Console.WriteLine('- named pipe ('+sPipeName+')');
Jens Geyer2ad6c302015-02-26 19:38:53 +0100662 namedpipe := TNamedPipeServerTransportImpl.Create( sPipeName, 4096, PIPE_UNLIMITED_INSTANCES);
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200663 servertrans := namedpipe;
664 end;
665
666 trns_AnonPipes : begin
667 Console.WriteLine('- anonymous pipes');
668 anonymouspipe := TAnonymousPipeServerTransportImpl.Create;
669 servertrans := anonymouspipe;
670 end
671
672 else
673 raise Exception.Create('Unhandled endpoint transport');
Roger Meier3bef8c22012-10-06 06:58:00 +0000674 end;
675 ASSERT( servertrans <> nil);
676
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200677 if UseSSL then begin
678 raise Exception.Create('SSL not implemented');
679 end;
680
681 if (trns_Framed in layered) then begin
Roger Meier3bef8c22012-10-06 06:58:00 +0000682 Console.WriteLine('- framed transport');
683 TransportFactory := TFramedTransportImpl.TFactory.Create
684 end
685 else begin
686 TransportFactory := TTransportFactoryImpl.Create;
687 end;
688 ASSERT( TransportFactory <> nil);
689
690 testHandler := TTestHandlerImpl.Create;
Jake Farrell27274222011-11-10 20:32:44 +0000691 testProcessor := TThriftTest.TProcessorImpl.Create( testHandler );
Jake Farrell27274222011-11-10 20:32:44 +0000692
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200693 case servertype of
694 srv_Simple : begin
695 ServerEngine := TSimpleServer.Create( testProcessor, ServerTrans, TransportFactory, ProtocolFactory);
696 end;
697
698 srv_Nonblocking : begin
699 raise Exception.Create(SERVER_TYPES[servertype]+' server not implemented');
700 end;
701
702 srv_Threadpool,
703 srv_Threaded: begin
704 if numWorker > 1 then {use here};
705 raise Exception.Create(SERVER_TYPES[servertype]+' server not implemented');
706 end;
707
708 else
709 raise Exception.Create('Unhandled server type');
710 end;
711 ASSERT( ServerEngine <> nil);
Jake Farrell27274222011-11-10 20:32:44 +0000712
713 testHandler.SetServer( ServerEngine);
714
Jens Geyer01640402013-09-25 21:12:21 +0200715 // test events?
716 if ServerEvents then begin
717 Console.WriteLine('- server events test enabled');
718 ServerEngine.ServerEvents := TServerEventsImpl.Create;
719 end;
720
Roger Meier3bef8c22012-10-06 06:58:00 +0000721 // start the client now when we have the anon handles, but before the server starts
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200722 if endpoint = trns_AnonPipes
Roger Meier79655fb2012-10-20 20:59:41 +0000723 then LaunchAnonPipeChild( ExtractFilePath(ParamStr(0))+'client.exe', anonymouspipe);
Jake Farrell27274222011-11-10 20:32:44 +0000724
Jens Geyer06045cf2013-03-27 20:26:25 +0200725 // install Ctrl+C handler before the server starts
726 g_Handler := testHandler;
727 SetConsoleCtrlHandler( @MyConsoleEventHandler, TRUE);
Roger Meier3bef8c22012-10-06 06:58:00 +0000728
729 Console.WriteLine('');
Jens Geyer06045cf2013-03-27 20:26:25 +0200730 repeat
731 Console.WriteLine('Starting the server ...');
732 serverEngine.Serve;
733 until {$IFDEF RunEndless} FALSE {$ELSE} TRUE {$ENDIF};
734
Jake Farrell27274222011-11-10 20:32:44 +0000735 testHandler.SetServer( nil);
Jens Geyer06045cf2013-03-27 20:26:25 +0200736 g_Handler := nil;
Jake Farrell27274222011-11-10 20:32:44 +0000737
738 except
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200739 on E: EAbort do raise;
740 on E: Exception do begin
741 Console.WriteLine( E.Message + #10 + E.StackTrace );
Jake Farrell27274222011-11-10 20:32:44 +0000742 end;
743 end;
744 Console.WriteLine( 'done.');
745end;
746
Jens Geyer06045cf2013-03-27 20:26:25 +0200747
Jake Farrell27274222011-11-10 20:32:44 +0000748end.