blob: 018282cca92aace5194f979d6307eaabe148d0de [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();
Jens Geyer39ba6b72015-09-22 00:00:49 +020061 function testBool(thing: Boolean): Boolean;
Roger Meier333bbf32012-01-08 21:51:08 +000062 function testString(const thing: string): string;
Jake Farrell7ae13e12011-10-18 14:35:26 +000063 function testByte(thing: ShortInt): ShortInt;
64 function testI32(thing: Integer): Integer;
Roger Meier333bbf32012-01-08 21:51:08 +000065 function testI64(const thing: Int64): Int64;
66 function testDouble(const thing: Double): Double;
Jens Geyerfd1b3582014-12-13 23:42:58 +010067 function testBinary(const thing: TBytes): TBytes;
Roger Meier333bbf32012-01-08 21:51:08 +000068 function testStruct(const thing: IXtruct): IXtruct;
69 function testNest(const thing: IXtruct2): IXtruct2;
70 function testMap(const thing: IThriftDictionary<Integer, Integer>): IThriftDictionary<Integer, Integer>;
71 function testStringMap(const thing: IThriftDictionary<string, string>): IThriftDictionary<string, string>;
72 function testSet(const thing: IHashSet<Integer>): IHashSet<Integer>;
73 function testList(const thing: IThriftList<Integer>): IThriftList<Integer>;
Jake Farrell7ae13e12011-10-18 14:35:26 +000074 function testEnum(thing: TNumberz): TNumberz;
Roger Meier333bbf32012-01-08 21:51:08 +000075 function testTypedef(const thing: Int64): Int64;
Jake Farrell7ae13e12011-10-18 14:35:26 +000076 function testMapMap(hello: Integer): IThriftDictionary<Integer, IThriftDictionary<Integer, Integer>>;
Roger Meier333bbf32012-01-08 21:51:08 +000077 function testInsanity(const argument: IInsanity): IThriftDictionary<Int64, IThriftDictionary<TNumberz, IInsanity>>;
78 function testMulti(arg0: ShortInt; arg1: Integer; const arg2: Int64; const arg3: IThriftDictionary<SmallInt, string>; arg4: TNumberz; const arg5: Int64): IXtruct;
79 procedure testException(const arg: string);
80 function testMultiException(const arg0: string; const arg1: string): IXtruct;
Jake Farrell7ae13e12011-10-18 14:35:26 +000081 procedure testOneway(secondsToSleep: Integer);
Jake Farrell27274222011-11-10 20:32:44 +000082
Jens Geyer06045cf2013-03-27 20:26:25 +020083 procedure TestStop;
Roger Meier333bbf32012-01-08 21:51:08 +000084 procedure SetServer( const AServer : IServer );
Jake Farrell27274222011-11-10 20:32:44 +000085 end;
86
Jens Geyerf8a1b7a2014-09-24 00:26:46 +020087 class procedure PrintCmdLineHelp;
88 class procedure InvalidArgs;
89
Jens Geyer06045cf2013-03-27 20:26:25 +020090 class procedure LaunchAnonPipeChild( const app : string; const transport : IAnonymousPipeServerTransport);
Roger Meier333bbf32012-01-08 21:51:08 +000091 class procedure Execute( const args: array of string);
Jake Farrell27274222011-11-10 20:32:44 +000092 end;
93
94implementation
95
Jens Geyer06045cf2013-03-27 20:26:25 +020096
97var g_Handler : TTestServer.ITestHandler = nil;
98
99
100function MyConsoleEventHandler( dwCtrlType : DWORD) : BOOL; stdcall;
101// Note that this Handler procedure is called from another thread
102var handler : TTestServer.ITestHandler;
103begin
104 result := TRUE;
105 try
106 case dwCtrlType of
107 CTRL_C_EVENT : Console.WriteLine( 'Ctrl+C pressed');
108 CTRL_BREAK_EVENT : Console.WriteLine( 'Ctrl+Break pressed');
109 CTRL_CLOSE_EVENT : Console.WriteLine( 'Received CloseTask signal');
110 CTRL_LOGOFF_EVENT : Console.WriteLine( 'Received LogOff signal');
111 CTRL_SHUTDOWN_EVENT : Console.WriteLine( 'Received Shutdown signal');
112 else
113 Console.WriteLine( 'Received console event #'+IntToStr(Integer(dwCtrlType)));
114 end;
115
116 handler := g_Handler;
117 if handler <> nil then handler.TestStop;
118
119 except
120 // catch all
121 end;
122end;
123
124
Jake Farrell27274222011-11-10 20:32:44 +0000125{ TTestServer.TTestHandlerImpl }
126
Roger Meier333bbf32012-01-08 21:51:08 +0000127procedure TTestServer.TTestHandlerImpl.SetServer( const AServer: IServer);
Jake Farrell27274222011-11-10 20:32:44 +0000128begin
129 FServer := AServer;
130end;
131
132function TTestServer.TTestHandlerImpl.testByte(thing: ShortInt): ShortInt;
133begin
134 Console.WriteLine('testByte("' + IntToStr( thing) + '")');
135 Result := thing;
136end;
137
Roger Meier333bbf32012-01-08 21:51:08 +0000138function TTestServer.TTestHandlerImpl.testDouble( const thing: Double): Double;
Jake Farrell27274222011-11-10 20:32:44 +0000139begin
140 Console.WriteLine('testDouble("' + FloatToStr( thing ) + '")');
141 Result := thing;
142end;
143
Jens Geyerfd1b3582014-12-13 23:42:58 +0100144function TTestServer.TTestHandlerImpl.testBinary(const thing: TBytes): TBytes;
145begin
146 Console.WriteLine('testBinary("' + BytesToHex( thing ) + '")');
147 Result := thing;
148end;
149
Jake Farrell27274222011-11-10 20:32:44 +0000150function TTestServer.TTestHandlerImpl.testEnum(thing: TNumberz): TNumberz;
151begin
152 Console.WriteLine('testEnum(' + IntToStr( Integer( thing)) + ')');
153 Result := thing;
154end;
155
Roger Meier333bbf32012-01-08 21:51:08 +0000156procedure TTestServer.TTestHandlerImpl.testException(const arg: string);
Jake Farrell27274222011-11-10 20:32:44 +0000157begin
158 Console.WriteLine('testException(' + arg + ')');
159 if ( arg = 'Xception') then
160 begin
Roger Meierbb6de7a2012-05-04 23:35:45 +0000161 raise TXception.Create( 1001, arg);
Jake Farrell27274222011-11-10 20:32:44 +0000162 end;
Roger Meierbb6de7a2012-05-04 23:35:45 +0000163
164 if (arg = 'TException') then
165 begin
166 raise TException.Create('');
167 end;
168
169 // else do not throw anything
Jake Farrell27274222011-11-10 20:32:44 +0000170end;
171
172function TTestServer.TTestHandlerImpl.testI32(thing: Integer): Integer;
173begin
174 Console.WriteLine('testI32("' + IntToStr( thing) + '")');
175 Result := thing;
176end;
177
Roger Meier333bbf32012-01-08 21:51:08 +0000178function TTestServer.TTestHandlerImpl.testI64( const thing: Int64): Int64;
Jake Farrell27274222011-11-10 20:32:44 +0000179begin
180 Console.WriteLine('testI64("' + IntToStr( thing) + '")');
181 Result := thing;
182end;
183
184function TTestServer.TTestHandlerImpl.testInsanity(
Roger Meier333bbf32012-01-08 21:51:08 +0000185 const argument: IInsanity): IThriftDictionary<Int64, IThriftDictionary<TNumberz, IInsanity>>;
Jake Farrell27274222011-11-10 20:32:44 +0000186var
187 hello, goodbye : IXtruct;
188 crazy : IInsanity;
189 looney : IInsanity;
190 first_map : IThriftDictionary<TNumberz, IInsanity>;
191 second_map : IThriftDictionary<TNumberz, IInsanity>;
192 insane : IThriftDictionary<Int64, IThriftDictionary<TNumberz, IInsanity>>;
193
194begin
195
196 Console.WriteLine('testInsanity()');
197 hello := TXtructImpl.Create;
Roger Meierbb6de7a2012-05-04 23:35:45 +0000198 hello.String_thing := 'Hello2';
Jake Farrell27274222011-11-10 20:32:44 +0000199 hello.Byte_thing := 2;
200 hello.I32_thing := 2;
201 hello.I64_thing := 2;
202
203 goodbye := TXtructImpl.Create;
204 goodbye.String_thing := 'Goodbye4';
205 goodbye.Byte_thing := 4;
206 goodbye.I32_thing := 4;
207 goodbye.I64_thing := 4;
208
209 crazy := TInsanityImpl.Create;
210 crazy.UserMap := TThriftDictionaryImpl<TNumberz, Int64>.Create;
211 crazy.UserMap.AddOrSetValue( TNumberz.EIGHT, 8);
212 crazy.Xtructs := TThriftListImpl<IXtruct>.Create;
213 crazy.Xtructs.Add(goodbye);
214
215 looney := TInsanityImpl.Create;
216 crazy.UserMap.AddOrSetValue( TNumberz.FIVE, 5);
217 crazy.Xtructs.Add(hello);
218
219 first_map := TThriftDictionaryImpl<TNumberz, IInsanity>.Create;
220 second_map := TThriftDictionaryImpl<TNumberz, IInsanity>.Create;
221
Roger Meierbb6de7a2012-05-04 23:35:45 +0000222 first_map.AddOrSetValue( TNumberz.TWO, crazy);
Jake Farrell27274222011-11-10 20:32:44 +0000223 first_map.AddOrSetValue( TNumberz.THREE, crazy);
224
225 second_map.AddOrSetValue( TNumberz.SIX, looney);
226
227 insane := TThriftDictionaryImpl<Int64, IThriftDictionary<TNumberz, IInsanity>>.Create;
228
229 insane.AddOrSetValue( 1, first_map);
230 insane.AddOrSetValue( 2, second_map);
231
232 Result := insane;
233end;
234
235function TTestServer.TTestHandlerImpl.testList(
Roger Meier333bbf32012-01-08 21:51:08 +0000236 const thing: IThriftList<Integer>): IThriftList<Integer>;
Jake Farrell27274222011-11-10 20:32:44 +0000237var
238 first : Boolean;
239 elem : Integer;
240begin
241 Console.Write('testList({');
242 first := True;
243 for elem in thing do
244 begin
245 if first then
246 begin
247 first := False;
248 end else
249 begin
250 Console.Write(', ');
251 end;
252 Console.Write( IntToStr( elem));
253 end;
254 Console.WriteLine('})');
255 Result := thing;
256end;
257
258function TTestServer.TTestHandlerImpl.testMap(
Roger Meier333bbf32012-01-08 21:51:08 +0000259 const thing: IThriftDictionary<Integer, Integer>): IThriftDictionary<Integer, Integer>;
Jake Farrell27274222011-11-10 20:32:44 +0000260var
261 first : Boolean;
262 key : Integer;
263begin
264 Console.Write('testMap({');
265 first := True;
266 for key in thing.Keys do
267 begin
268 if (first) then
269 begin
270 first := false;
271 end else
272 begin
273 Console.Write(', ');
274 end;
275 Console.Write(IntToStr(key) + ' => ' + IntToStr( thing[key]));
276 end;
277 Console.WriteLine('})');
278 Result := thing;
279end;
280
281function TTestServer.TTestHandlerImpl.TestMapMap(
282 hello: Integer): IThriftDictionary<Integer, IThriftDictionary<Integer, Integer>>;
283var
284 mapmap : IThriftDictionary<Integer, IThriftDictionary<Integer, Integer>>;
285 pos : IThriftDictionary<Integer, Integer>;
286 neg : IThriftDictionary<Integer, Integer>;
287 i : Integer;
288begin
289 Console.WriteLine('testMapMap(' + IntToStr( hello) + ')');
290 mapmap := TThriftDictionaryImpl<Integer, IThriftDictionary<Integer, Integer>>.Create;
291 pos := TThriftDictionaryImpl<Integer, Integer>.Create;
292 neg := TThriftDictionaryImpl<Integer, Integer>.Create;
293
294 for i := 1 to 4 do
295 begin
296 pos.AddOrSetValue( i, i);
297 neg.AddOrSetValue( -i, -i);
298 end;
299
300 mapmap.AddOrSetValue(4, pos);
301 mapmap.AddOrSetValue( -4, neg);
302
303 Result := mapmap;
304end;
305
306function TTestServer.TTestHandlerImpl.testMulti(arg0: ShortInt; arg1: Integer;
Roger Meier333bbf32012-01-08 21:51:08 +0000307 const arg2: Int64; const arg3: IThriftDictionary<SmallInt, string>;
308 arg4: TNumberz; const arg5: Int64): IXtruct;
Jake Farrell27274222011-11-10 20:32:44 +0000309var
310 hello : IXtruct;
311begin
312 Console.WriteLine('testMulti()');
313 hello := TXtructImpl.Create;
314 hello.String_thing := 'Hello2';
315 hello.Byte_thing := arg0;
316 hello.I32_thing := arg1;
317 hello.I64_thing := arg2;
318 Result := hello;
319end;
320
Roger Meier333bbf32012-01-08 21:51:08 +0000321function TTestServer.TTestHandlerImpl.testMultiException( const arg0, arg1: string): IXtruct;
Jake Farrell27274222011-11-10 20:32:44 +0000322var
Jake Farrell27274222011-11-10 20:32:44 +0000323 x2 : TXception2;
324begin
325 Console.WriteLine('testMultiException(' + arg0 + ', ' + arg1 + ')');
326 if ( arg0 = 'Xception') then
327 begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200328 raise TXception.Create( 1001, 'This is an Xception'); // test the new rich CTOR
Jake Farrell27274222011-11-10 20:32:44 +0000329 end else
330 if ( arg0 = 'Xception2') then
331 begin
Jake Farrell343c61d2011-12-09 02:29:56 +0000332 x2 := TXception2.Create; // the old way still works too?
Jake Farrell27274222011-11-10 20:32:44 +0000333 x2.ErrorCode := 2002;
334 x2.Struct_thing := TXtructImpl.Create;
335 x2.Struct_thing.String_thing := 'This is an Xception2';
Jake Farrellac102562011-11-23 14:30:41 +0000336 x2.UpdateMessageProperty;
Jake Farrell27274222011-11-10 20:32:44 +0000337 raise x2;
338 end;
339
340 Result := TXtructImpl.Create;
341 Result.String_thing := arg1;
342end;
343
Roger Meier333bbf32012-01-08 21:51:08 +0000344function TTestServer.TTestHandlerImpl.testNest( const thing: IXtruct2): IXtruct2;
Jake Farrell27274222011-11-10 20:32:44 +0000345var
346 temp : IXtruct;
347begin
348 temp := thing.Struct_thing;
349 Console.WriteLine('testNest({' +
350 IntToStr( thing.Byte_thing) + ', {' +
351 '"' + temp.String_thing + '", ' +
352 IntToStr( temp.Byte_thing) + ', ' +
353 IntToStr( temp.I32_thing) + ', ' +
354 IntToStr( temp.I64_thing) + '}, ' +
355 IntToStr( temp.I32_thing) + '})');
356 Result := thing;
357end;
358
359procedure TTestServer.TTestHandlerImpl.testOneway(secondsToSleep: Integer);
360begin
361 Console.WriteLine('testOneway(' + IntToStr( secondsToSleep )+ '), sleeping...');
362 Sleep(secondsToSleep * 1000);
363 Console.WriteLine('testOneway finished');
364end;
365
366function TTestServer.TTestHandlerImpl.testSet(
Roger Meier333bbf32012-01-08 21:51:08 +0000367 const thing: IHashSet<Integer>):IHashSet<Integer>;
Jake Farrell27274222011-11-10 20:32:44 +0000368var
369 first : Boolean;
370 elem : Integer;
371begin
372 Console.Write('testSet({');
373 first := True;
374
375 for elem in thing do
376 begin
377 if first then
378 begin
379 first := False;
380 end else
381 begin
382 Console.Write( ', ');
383 end;
384 Console.Write( IntToStr( elem));
385 end;
386 Console.WriteLine('})');
387 Result := thing;
388end;
389
390procedure TTestServer.TTestHandlerImpl.testStop;
391begin
392 if FServer <> nil then
393 begin
394 FServer.Stop;
395 end;
396end;
397
Jens Geyer39ba6b72015-09-22 00:00:49 +0200398function TTestServer.TTestHandlerImpl.testBool(thing: Boolean): Boolean;
399begin
400 Console.WriteLine('testBool(' + BoolToStr(thing,true) + ')');
401 Result := thing;
402end;
403
Roger Meier333bbf32012-01-08 21:51:08 +0000404function TTestServer.TTestHandlerImpl.testString( const thing: string): string;
Jake Farrell27274222011-11-10 20:32:44 +0000405begin
406 Console.WriteLine('teststring("' + thing + '")');
407 Result := thing;
408end;
409
410function TTestServer.TTestHandlerImpl.testStringMap(
Roger Meier333bbf32012-01-08 21:51:08 +0000411 const thing: IThriftDictionary<string, string>): IThriftDictionary<string, string>;
Roger Meierbb6de7a2012-05-04 23:35:45 +0000412var
413 first : Boolean;
414 key : string;
Jake Farrell27274222011-11-10 20:32:44 +0000415begin
Roger Meierbb6de7a2012-05-04 23:35:45 +0000416 Console.Write('testStringMap({');
417 first := True;
418 for key in thing.Keys do
419 begin
420 if (first) then
421 begin
422 first := false;
423 end else
424 begin
425 Console.Write(', ');
426 end;
427 Console.Write(key + ' => ' + thing[key]);
428 end;
429 Console.WriteLine('})');
430 Result := thing;
Jake Farrell27274222011-11-10 20:32:44 +0000431end;
432
Roger Meier333bbf32012-01-08 21:51:08 +0000433function TTestServer.TTestHandlerImpl.testTypedef( const thing: Int64): Int64;
Jake Farrell27274222011-11-10 20:32:44 +0000434begin
435 Console.WriteLine('testTypedef(' + IntToStr( thing) + ')');
436 Result := thing;
437end;
438
439procedure TTestServer.TTestHandlerImpl.TestVoid;
440begin
441 Console.WriteLine('testVoid()');
442end;
443
Roger Meier333bbf32012-01-08 21:51:08 +0000444function TTestServer.TTestHandlerImpl.testStruct( const thing: IXtruct): IXtruct;
Jake Farrell27274222011-11-10 20:32:44 +0000445begin
446 Console.WriteLine('testStruct({' +
447 '"' + thing.String_thing + '", ' +
448 IntToStr( thing.Byte_thing) + ', ' +
449 IntToStr( thing.I32_thing) + ', ' +
450 IntToStr( thing.I64_thing));
451 Result := thing;
452end;
453
Roger Meier3bef8c22012-10-06 06:58:00 +0000454
Jake Farrell27274222011-11-10 20:32:44 +0000455{ TTestServer }
456
Roger Meier3bef8c22012-10-06 06:58:00 +0000457
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200458class procedure TTestServer.PrintCmdLineHelp;
459const HELPTEXT = ' [options]'#10
460 + #10
461 + 'Allowed options:'#10
462 + ' -h [ --help ] produce help message'#10
463 + ' --port arg (=9090) Port number to listen'#10
464 + ' --domain-socket arg Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)'#10
465 + ' --named-pipe arg Windows Named Pipe (e.g. MyThriftPipe)'#10
466 + ' --server-type arg (=simple) type of server, "simple", "thread-pool",'#10
467 + ' "threaded", or "nonblocking"'#10
468 + ' --transport arg (=socket) transport: buffered, framed, http, anonpipe'#10
469 + ' --protocol arg (=binary) protocol: binary, compact, json'#10
470 + ' --ssl Encrypted Transport using SSL'#10
471 + ' --processor-events processor-events'#10
472 + ' -n [ --workers ] arg (=4) Number of thread pools workers. Only valid for'#10
473 + ' thread-pool server type'#10
474 ;
475begin
476 Console.WriteLine( ChangeFileExt(ExtractFileName(ParamStr(0)),'') + HELPTEXT);
477end;
478
479class procedure TTestServer.InvalidArgs;
480begin
481 Console.WriteLine( 'Invalid args.');
482 Console.WriteLine( ChangeFileExt(ExtractFileName(ParamStr(0)),'') + ' -h for more information');
483 Abort;
484end;
485
Jens Geyer06045cf2013-03-27 20:26:25 +0200486class procedure TTestServer.LaunchAnonPipeChild( const app : string; const transport : IAnonymousPipeServerTransport);
Roger Meier3bef8c22012-10-06 06:58:00 +0000487//Launch child process and pass R/W anonymous pipe handles on cmd line.
488//This is a simple example and does not include elevation or other
489//advanced features.
490var pi : PROCESS_INFORMATION;
Jens Geyerd5436f52014-10-03 19:50:38 +0200491 si : STARTUPINFO;
492 sArg, sHandles, sCmdLine : string;
Roger Meier3bef8c22012-10-06 06:58:00 +0000493 i : Integer;
494begin
495 GetStartupInfo( si); //set startupinfo for the spawned process
496
497 // preformat handles args
498 sHandles := Format( '%d %d',
499 [ Integer(transport.ClientAnonRead),
500 Integer(transport.ClientAnonWrite)]);
501
502 // pass all settings to client
503 sCmdLine := app;
504 for i := 1 to ParamCount do begin
505 sArg := ParamStr(i);
506
507 // add anonymous handles and quote strings where appropriate
508 if sArg = '-anon'
509 then sArg := sArg +' '+ sHandles
510 else begin
511 if Pos(' ',sArg) > 0
512 then sArg := '"'+sArg+'"';
513 end;;
514
515 sCmdLine := sCmdLine +' '+ sArg;
516 end;
517
518 // spawn the child process
519 Console.WriteLine('Starting client '+sCmdLine);
520 Win32Check( CreateProcess( nil, PChar(sCmdLine), nil,nil,TRUE,0,nil,nil,si,pi));
521
522 CloseHandle( pi.hThread);
Jens Geyerd5436f52014-10-03 19:50:38 +0200523 CloseHandle( pi.hProcess);
Roger Meier3bef8c22012-10-06 06:58:00 +0000524end;
525
526
Roger Meier333bbf32012-01-08 21:51:08 +0000527class procedure TTestServer.Execute( const args: array of string);
Jake Farrell27274222011-11-10 20:32:44 +0000528var
Jake Farrell27274222011-11-10 20:32:44 +0000529 Port : Integer;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200530 ServerEvents : Boolean;
Roger Meier3bef8c22012-10-06 06:58:00 +0000531 sPipeName : string;
Jake Farrell27274222011-11-10 20:32:44 +0000532 testHandler : ITestHandler;
533 testProcessor : IProcessor;
Roger Meier3bef8c22012-10-06 06:58:00 +0000534 ServerTrans : IServerTransport;
Jake Farrell27274222011-11-10 20:32:44 +0000535 ServerEngine : IServer;
Jens Geyer06045cf2013-03-27 20:26:25 +0200536 anonymouspipe : IAnonymousPipeServerTransport;
537 namedpipe : INamedPipeServerTransport;
Jake Farrell27274222011-11-10 20:32:44 +0000538 TransportFactory : ITransportFactory;
539 ProtocolFactory : IProtocolFactory;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200540 i, numWorker : Integer;
Jake Farrell27274222011-11-10 20:32:44 +0000541 s : string;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200542 protType : TKnownProtocol;
543 servertype : TServerType;
544 endpoint : TEndpointTransport;
545 layered : TLayeredTransports;
546 UseSSL : Boolean; // include where appropriate (TLayeredTransport?)
Jake Farrell27274222011-11-10 20:32:44 +0000547begin
548 try
Jens Geyer01640402013-09-25 21:12:21 +0200549 ServerEvents := FALSE;
Jake Farrell27274222011-11-10 20:32:44 +0000550 protType := prot_Binary;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200551 servertype := srv_Simple;
552 endpoint := trns_Sockets;
553 layered := [];
554 UseSSL := FALSE;
Jake Farrell27274222011-11-10 20:32:44 +0000555 Port := 9090;
Roger Meier3bef8c22012-10-06 06:58:00 +0000556 sPipeName := '';
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200557 numWorker := 4;
Jake Farrell27274222011-11-10 20:32:44 +0000558
559 i := 0;
560 while ( i < Length(args) ) do begin
561 s := args[i];
562 Inc(i);
563
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200564 // Allowed options:
565 if (s = '-h') or (s = '--help') then begin
566 // -h [ --help ] produce help message
567 PrintCmdLineHelp;
568 Exit;
Roger Meier3bef8c22012-10-06 06:58:00 +0000569 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200570 else if (s = '--port') then begin
571 // --port arg (=9090) Port number to listen
572 s := args[i];
573 Inc(i);
574 Port := StrToIntDef( s, Port);
Roger Meier3bef8c22012-10-06 06:58:00 +0000575 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200576 else if (s = '--domain-socket') then begin
577 // --domain-socket arg Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)
578 raise Exception.Create('domain-socket not supported');
Roger Meier3bef8c22012-10-06 06:58:00 +0000579 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200580 else if (s = '--named-pipe') then begin
581 // --named-pipe arg Windows Named Pipe (e.g. MyThriftPipe)
582 endpoint := trns_NamedPipes;
Roger Meier3bef8c22012-10-06 06:58:00 +0000583 sPipeName := args[i]; // -pipe <name>
584 Inc( i );
585 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200586 else if (s = '--server-type') then begin
587 // --server-type arg (=simple) type of server,
588 // arg = "simple", "thread-pool", "threaded", or "nonblocking"
Jake Farrell27274222011-11-10 20:32:44 +0000589 s := args[i];
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200590 Inc(i);
591
592 if s = 'simple' then servertype := srv_Simple
593 else if s = 'thread-pool' then servertype := srv_Threadpool
594 else if s = 'threaded' then servertype := srv_Threaded
595 else if s = 'nonblocking' then servertype := srv_Nonblocking
596 else InvalidArgs;
Jens Geyer01640402013-09-25 21:12:21 +0200597 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200598 else if (s = '--transport') then begin
599 // --transport arg (=buffered) transport: buffered, framed, http
600 s := args[i];
601 Inc(i);
602
603 if s = 'buffered' then Include( layered, trns_Buffered)
604 else if s = 'framed' then Include( layered, trns_Framed)
605 else if s = 'http' then endpoint := trns_Http
606 else if s = 'anonpipe' then endpoint := trns_AnonPipes
607 else InvalidArgs;
608 end
609 else if (s = '--protocol') then begin
610 // --protocol arg (=binary) protocol: binary, compact, json
611 s := args[i];
612 Inc(i);
613
614 if s = 'binary' then protType := prot_Binary
615 else if s = 'compact' then protType := prot_Compact
616 else if s = 'json' then protType := prot_JSON
617 else InvalidArgs;
618 end
619 else if (s = '--ssl') then begin
620 // --ssl Encrypted Transport using SSL
621 UseSSL := TRUE;
622 end
623 else if (s = '--processor-events') then begin
624 // --processor-events processor-events
625 ServerEvents := TRUE;
626 end
627 else if (s = '-n') or (s = '--workers') then begin
628 // -n [ --workers ] arg (=4) Number of thread pools workers.
629 // Only valid for thread-pool server type
630 s := args[i];
631 numWorker := StrToIntDef(s,0);
632 if numWorker > 0
633 then Inc(i)
634 else numWorker := 4;
Jens Geyer01640402013-09-25 21:12:21 +0200635 end
636 else begin
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200637 InvalidArgs;
638 end;
Jake Farrell27274222011-11-10 20:32:44 +0000639 end;
640
Roger Meier3bef8c22012-10-06 06:58:00 +0000641
642 Console.WriteLine('Server configuration: ');
643
Jake Farrell27274222011-11-10 20:32:44 +0000644 // create protocol factory, default to BinaryProtocol
645 case protType of
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200646 prot_Binary : ProtocolFactory := TBinaryProtocolImpl.TFactory.Create( BINARY_STRICT_READ, BINARY_STRICT_WRITE);
647 prot_JSON : ProtocolFactory := TJSONProtocolImpl.TFactory.Create;
Jens Geyerf0e63312015-03-01 18:47:49 +0100648 prot_Compact : ProtocolFactory := TCompactProtocolImpl.TFactory.Create;
Jake Farrell27274222011-11-10 20:32:44 +0000649 else
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200650 raise Exception.Create('Unhandled protocol');
Jake Farrell27274222011-11-10 20:32:44 +0000651 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000652 ASSERT( ProtocolFactory <> nil);
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200653 Console.WriteLine('- '+THRIFT_PROTOCOLS[protType]+' protocol');
Jake Farrell27274222011-11-10 20:32:44 +0000654
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200655 case endpoint of
Jake Farrell27274222011-11-10 20:32:44 +0000656
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200657 trns_Sockets : begin
658 Console.WriteLine('- sockets (port '+IntToStr(port)+')');
659 if (trns_Buffered in layered) then Console.WriteLine('- buffered');
660 servertrans := TServerSocketImpl.Create( Port, 0, (trns_Buffered in layered));
661 end;
662
663 trns_Http : begin
664 raise Exception.Create('HTTP server transport not implemented');
665 end;
666
667 trns_NamedPipes : begin
668 Console.WriteLine('- named pipe ('+sPipeName+')');
Jens Geyer2ad6c302015-02-26 19:38:53 +0100669 namedpipe := TNamedPipeServerTransportImpl.Create( sPipeName, 4096, PIPE_UNLIMITED_INSTANCES);
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200670 servertrans := namedpipe;
671 end;
672
673 trns_AnonPipes : begin
674 Console.WriteLine('- anonymous pipes');
675 anonymouspipe := TAnonymousPipeServerTransportImpl.Create;
676 servertrans := anonymouspipe;
677 end
678
679 else
680 raise Exception.Create('Unhandled endpoint transport');
Roger Meier3bef8c22012-10-06 06:58:00 +0000681 end;
682 ASSERT( servertrans <> nil);
683
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200684 if UseSSL then begin
685 raise Exception.Create('SSL not implemented');
686 end;
687
688 if (trns_Framed in layered) then begin
Roger Meier3bef8c22012-10-06 06:58:00 +0000689 Console.WriteLine('- framed transport');
690 TransportFactory := TFramedTransportImpl.TFactory.Create
691 end
692 else begin
693 TransportFactory := TTransportFactoryImpl.Create;
694 end;
695 ASSERT( TransportFactory <> nil);
696
697 testHandler := TTestHandlerImpl.Create;
Jake Farrell27274222011-11-10 20:32:44 +0000698 testProcessor := TThriftTest.TProcessorImpl.Create( testHandler );
Jake Farrell27274222011-11-10 20:32:44 +0000699
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200700 case servertype of
701 srv_Simple : begin
702 ServerEngine := TSimpleServer.Create( testProcessor, ServerTrans, TransportFactory, ProtocolFactory);
703 end;
704
705 srv_Nonblocking : begin
706 raise Exception.Create(SERVER_TYPES[servertype]+' server not implemented');
707 end;
708
709 srv_Threadpool,
710 srv_Threaded: begin
711 if numWorker > 1 then {use here};
712 raise Exception.Create(SERVER_TYPES[servertype]+' server not implemented');
713 end;
714
715 else
716 raise Exception.Create('Unhandled server type');
717 end;
718 ASSERT( ServerEngine <> nil);
Jake Farrell27274222011-11-10 20:32:44 +0000719
720 testHandler.SetServer( ServerEngine);
721
Jens Geyer01640402013-09-25 21:12:21 +0200722 // test events?
723 if ServerEvents then begin
724 Console.WriteLine('- server events test enabled');
725 ServerEngine.ServerEvents := TServerEventsImpl.Create;
726 end;
727
Roger Meier3bef8c22012-10-06 06:58:00 +0000728 // start the client now when we have the anon handles, but before the server starts
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200729 if endpoint = trns_AnonPipes
Roger Meier79655fb2012-10-20 20:59:41 +0000730 then LaunchAnonPipeChild( ExtractFilePath(ParamStr(0))+'client.exe', anonymouspipe);
Jake Farrell27274222011-11-10 20:32:44 +0000731
Jens Geyer06045cf2013-03-27 20:26:25 +0200732 // install Ctrl+C handler before the server starts
733 g_Handler := testHandler;
734 SetConsoleCtrlHandler( @MyConsoleEventHandler, TRUE);
Roger Meier3bef8c22012-10-06 06:58:00 +0000735
736 Console.WriteLine('');
Jens Geyer06045cf2013-03-27 20:26:25 +0200737 repeat
738 Console.WriteLine('Starting the server ...');
739 serverEngine.Serve;
740 until {$IFDEF RunEndless} FALSE {$ELSE} TRUE {$ENDIF};
741
Jake Farrell27274222011-11-10 20:32:44 +0000742 testHandler.SetServer( nil);
Jens Geyer06045cf2013-03-27 20:26:25 +0200743 g_Handler := nil;
Jake Farrell27274222011-11-10 20:32:44 +0000744
745 except
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200746 on E: EAbort do raise;
747 on E: Exception do begin
748 Console.WriteLine( E.Message + #10 + E.StackTrace );
Jake Farrell27274222011-11-10 20:32:44 +0000749 end;
750 end;
751 Console.WriteLine( 'done.');
752end;
753
Jens Geyer06045cf2013-03-27 20:26:25 +0200754
Jake Farrell27274222011-11-10 20:32:44 +0000755end.