blob: 35f1ac881c82f713c6e63b96388bbaf8d9f524c4 [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;
65 function testStruct(const thing: IXtruct): IXtruct;
66 function testNest(const thing: IXtruct2): IXtruct2;
67 function testMap(const thing: IThriftDictionary<Integer, Integer>): IThriftDictionary<Integer, Integer>;
68 function testStringMap(const thing: IThriftDictionary<string, string>): IThriftDictionary<string, string>;
69 function testSet(const thing: IHashSet<Integer>): IHashSet<Integer>;
70 function testList(const thing: IThriftList<Integer>): IThriftList<Integer>;
Jake Farrell7ae13e12011-10-18 14:35:26 +000071 function testEnum(thing: TNumberz): TNumberz;
Roger Meier333bbf32012-01-08 21:51:08 +000072 function testTypedef(const thing: Int64): Int64;
Jake Farrell7ae13e12011-10-18 14:35:26 +000073 function testMapMap(hello: Integer): IThriftDictionary<Integer, IThriftDictionary<Integer, Integer>>;
Roger Meier333bbf32012-01-08 21:51:08 +000074 function testInsanity(const argument: IInsanity): IThriftDictionary<Int64, IThriftDictionary<TNumberz, IInsanity>>;
75 function testMulti(arg0: ShortInt; arg1: Integer; const arg2: Int64; const arg3: IThriftDictionary<SmallInt, string>; arg4: TNumberz; const arg5: Int64): IXtruct;
76 procedure testException(const arg: string);
77 function testMultiException(const arg0: string; const arg1: string): IXtruct;
Jake Farrell7ae13e12011-10-18 14:35:26 +000078 procedure testOneway(secondsToSleep: Integer);
Jake Farrell27274222011-11-10 20:32:44 +000079
Jens Geyer06045cf2013-03-27 20:26:25 +020080 procedure TestStop;
Roger Meier333bbf32012-01-08 21:51:08 +000081 procedure SetServer( const AServer : IServer );
Jake Farrell27274222011-11-10 20:32:44 +000082 end;
83
Jens Geyerf8a1b7a2014-09-24 00:26:46 +020084 class procedure PrintCmdLineHelp;
85 class procedure InvalidArgs;
86
Jens Geyer06045cf2013-03-27 20:26:25 +020087 class procedure LaunchAnonPipeChild( const app : string; const transport : IAnonymousPipeServerTransport);
Roger Meier333bbf32012-01-08 21:51:08 +000088 class procedure Execute( const args: array of string);
Jake Farrell27274222011-11-10 20:32:44 +000089 end;
90
91implementation
92
Jens Geyer06045cf2013-03-27 20:26:25 +020093
94var g_Handler : TTestServer.ITestHandler = nil;
95
96
97function MyConsoleEventHandler( dwCtrlType : DWORD) : BOOL; stdcall;
98// Note that this Handler procedure is called from another thread
99var handler : TTestServer.ITestHandler;
100begin
101 result := TRUE;
102 try
103 case dwCtrlType of
104 CTRL_C_EVENT : Console.WriteLine( 'Ctrl+C pressed');
105 CTRL_BREAK_EVENT : Console.WriteLine( 'Ctrl+Break pressed');
106 CTRL_CLOSE_EVENT : Console.WriteLine( 'Received CloseTask signal');
107 CTRL_LOGOFF_EVENT : Console.WriteLine( 'Received LogOff signal');
108 CTRL_SHUTDOWN_EVENT : Console.WriteLine( 'Received Shutdown signal');
109 else
110 Console.WriteLine( 'Received console event #'+IntToStr(Integer(dwCtrlType)));
111 end;
112
113 handler := g_Handler;
114 if handler <> nil then handler.TestStop;
115
116 except
117 // catch all
118 end;
119end;
120
121
Jake Farrell27274222011-11-10 20:32:44 +0000122{ TTestServer.TTestHandlerImpl }
123
Roger Meier333bbf32012-01-08 21:51:08 +0000124procedure TTestServer.TTestHandlerImpl.SetServer( const AServer: IServer);
Jake Farrell27274222011-11-10 20:32:44 +0000125begin
126 FServer := AServer;
127end;
128
129function TTestServer.TTestHandlerImpl.testByte(thing: ShortInt): ShortInt;
130begin
131 Console.WriteLine('testByte("' + IntToStr( thing) + '")');
132 Result := thing;
133end;
134
Roger Meier333bbf32012-01-08 21:51:08 +0000135function TTestServer.TTestHandlerImpl.testDouble( const thing: Double): Double;
Jake Farrell27274222011-11-10 20:32:44 +0000136begin
137 Console.WriteLine('testDouble("' + FloatToStr( thing ) + '")');
138 Result := thing;
139end;
140
141function TTestServer.TTestHandlerImpl.testEnum(thing: TNumberz): TNumberz;
142begin
143 Console.WriteLine('testEnum(' + IntToStr( Integer( thing)) + ')');
144 Result := thing;
145end;
146
Roger Meier333bbf32012-01-08 21:51:08 +0000147procedure TTestServer.TTestHandlerImpl.testException(const arg: string);
Jake Farrell27274222011-11-10 20:32:44 +0000148begin
149 Console.WriteLine('testException(' + arg + ')');
150 if ( arg = 'Xception') then
151 begin
Roger Meierbb6de7a2012-05-04 23:35:45 +0000152 raise TXception.Create( 1001, arg);
Jake Farrell27274222011-11-10 20:32:44 +0000153 end;
Roger Meierbb6de7a2012-05-04 23:35:45 +0000154
155 if (arg = 'TException') then
156 begin
157 raise TException.Create('');
158 end;
159
160 // else do not throw anything
Jake Farrell27274222011-11-10 20:32:44 +0000161end;
162
163function TTestServer.TTestHandlerImpl.testI32(thing: Integer): Integer;
164begin
165 Console.WriteLine('testI32("' + IntToStr( thing) + '")');
166 Result := thing;
167end;
168
Roger Meier333bbf32012-01-08 21:51:08 +0000169function TTestServer.TTestHandlerImpl.testI64( const thing: Int64): Int64;
Jake Farrell27274222011-11-10 20:32:44 +0000170begin
171 Console.WriteLine('testI64("' + IntToStr( thing) + '")');
172 Result := thing;
173end;
174
175function TTestServer.TTestHandlerImpl.testInsanity(
Roger Meier333bbf32012-01-08 21:51:08 +0000176 const argument: IInsanity): IThriftDictionary<Int64, IThriftDictionary<TNumberz, IInsanity>>;
Jake Farrell27274222011-11-10 20:32:44 +0000177var
178 hello, goodbye : IXtruct;
179 crazy : IInsanity;
180 looney : IInsanity;
181 first_map : IThriftDictionary<TNumberz, IInsanity>;
182 second_map : IThriftDictionary<TNumberz, IInsanity>;
183 insane : IThriftDictionary<Int64, IThriftDictionary<TNumberz, IInsanity>>;
184
185begin
186
187 Console.WriteLine('testInsanity()');
188 hello := TXtructImpl.Create;
Roger Meierbb6de7a2012-05-04 23:35:45 +0000189 hello.String_thing := 'Hello2';
Jake Farrell27274222011-11-10 20:32:44 +0000190 hello.Byte_thing := 2;
191 hello.I32_thing := 2;
192 hello.I64_thing := 2;
193
194 goodbye := TXtructImpl.Create;
195 goodbye.String_thing := 'Goodbye4';
196 goodbye.Byte_thing := 4;
197 goodbye.I32_thing := 4;
198 goodbye.I64_thing := 4;
199
200 crazy := TInsanityImpl.Create;
201 crazy.UserMap := TThriftDictionaryImpl<TNumberz, Int64>.Create;
202 crazy.UserMap.AddOrSetValue( TNumberz.EIGHT, 8);
203 crazy.Xtructs := TThriftListImpl<IXtruct>.Create;
204 crazy.Xtructs.Add(goodbye);
205
206 looney := TInsanityImpl.Create;
207 crazy.UserMap.AddOrSetValue( TNumberz.FIVE, 5);
208 crazy.Xtructs.Add(hello);
209
210 first_map := TThriftDictionaryImpl<TNumberz, IInsanity>.Create;
211 second_map := TThriftDictionaryImpl<TNumberz, IInsanity>.Create;
212
Roger Meierbb6de7a2012-05-04 23:35:45 +0000213 first_map.AddOrSetValue( TNumberz.TWO, crazy);
Jake Farrell27274222011-11-10 20:32:44 +0000214 first_map.AddOrSetValue( TNumberz.THREE, crazy);
215
216 second_map.AddOrSetValue( TNumberz.SIX, looney);
217
218 insane := TThriftDictionaryImpl<Int64, IThriftDictionary<TNumberz, IInsanity>>.Create;
219
220 insane.AddOrSetValue( 1, first_map);
221 insane.AddOrSetValue( 2, second_map);
222
223 Result := insane;
224end;
225
226function TTestServer.TTestHandlerImpl.testList(
Roger Meier333bbf32012-01-08 21:51:08 +0000227 const thing: IThriftList<Integer>): IThriftList<Integer>;
Jake Farrell27274222011-11-10 20:32:44 +0000228var
229 first : Boolean;
230 elem : Integer;
231begin
232 Console.Write('testList({');
233 first := True;
234 for elem in thing do
235 begin
236 if first then
237 begin
238 first := False;
239 end else
240 begin
241 Console.Write(', ');
242 end;
243 Console.Write( IntToStr( elem));
244 end;
245 Console.WriteLine('})');
246 Result := thing;
247end;
248
249function TTestServer.TTestHandlerImpl.testMap(
Roger Meier333bbf32012-01-08 21:51:08 +0000250 const thing: IThriftDictionary<Integer, Integer>): IThriftDictionary<Integer, Integer>;
Jake Farrell27274222011-11-10 20:32:44 +0000251var
252 first : Boolean;
253 key : Integer;
254begin
255 Console.Write('testMap({');
256 first := True;
257 for key in thing.Keys do
258 begin
259 if (first) then
260 begin
261 first := false;
262 end else
263 begin
264 Console.Write(', ');
265 end;
266 Console.Write(IntToStr(key) + ' => ' + IntToStr( thing[key]));
267 end;
268 Console.WriteLine('})');
269 Result := thing;
270end;
271
272function TTestServer.TTestHandlerImpl.TestMapMap(
273 hello: Integer): IThriftDictionary<Integer, IThriftDictionary<Integer, Integer>>;
274var
275 mapmap : IThriftDictionary<Integer, IThriftDictionary<Integer, Integer>>;
276 pos : IThriftDictionary<Integer, Integer>;
277 neg : IThriftDictionary<Integer, Integer>;
278 i : Integer;
279begin
280 Console.WriteLine('testMapMap(' + IntToStr( hello) + ')');
281 mapmap := TThriftDictionaryImpl<Integer, IThriftDictionary<Integer, Integer>>.Create;
282 pos := TThriftDictionaryImpl<Integer, Integer>.Create;
283 neg := TThriftDictionaryImpl<Integer, Integer>.Create;
284
285 for i := 1 to 4 do
286 begin
287 pos.AddOrSetValue( i, i);
288 neg.AddOrSetValue( -i, -i);
289 end;
290
291 mapmap.AddOrSetValue(4, pos);
292 mapmap.AddOrSetValue( -4, neg);
293
294 Result := mapmap;
295end;
296
297function TTestServer.TTestHandlerImpl.testMulti(arg0: ShortInt; arg1: Integer;
Roger Meier333bbf32012-01-08 21:51:08 +0000298 const arg2: Int64; const arg3: IThriftDictionary<SmallInt, string>;
299 arg4: TNumberz; const arg5: Int64): IXtruct;
Jake Farrell27274222011-11-10 20:32:44 +0000300var
301 hello : IXtruct;
302begin
303 Console.WriteLine('testMulti()');
304 hello := TXtructImpl.Create;
305 hello.String_thing := 'Hello2';
306 hello.Byte_thing := arg0;
307 hello.I32_thing := arg1;
308 hello.I64_thing := arg2;
309 Result := hello;
310end;
311
Roger Meier333bbf32012-01-08 21:51:08 +0000312function TTestServer.TTestHandlerImpl.testMultiException( const arg0, arg1: string): IXtruct;
Jake Farrell27274222011-11-10 20:32:44 +0000313var
Jake Farrell27274222011-11-10 20:32:44 +0000314 x2 : TXception2;
315begin
316 Console.WriteLine('testMultiException(' + arg0 + ', ' + arg1 + ')');
317 if ( arg0 = 'Xception') then
318 begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200319 raise TXception.Create( 1001, 'This is an Xception'); // test the new rich CTOR
Jake Farrell27274222011-11-10 20:32:44 +0000320 end else
321 if ( arg0 = 'Xception2') then
322 begin
Jake Farrell343c61d2011-12-09 02:29:56 +0000323 x2 := TXception2.Create; // the old way still works too?
Jake Farrell27274222011-11-10 20:32:44 +0000324 x2.ErrorCode := 2002;
325 x2.Struct_thing := TXtructImpl.Create;
326 x2.Struct_thing.String_thing := 'This is an Xception2';
Jake Farrellac102562011-11-23 14:30:41 +0000327 x2.UpdateMessageProperty;
Jake Farrell27274222011-11-10 20:32:44 +0000328 raise x2;
329 end;
330
331 Result := TXtructImpl.Create;
332 Result.String_thing := arg1;
333end;
334
Roger Meier333bbf32012-01-08 21:51:08 +0000335function TTestServer.TTestHandlerImpl.testNest( const thing: IXtruct2): IXtruct2;
Jake Farrell27274222011-11-10 20:32:44 +0000336var
337 temp : IXtruct;
338begin
339 temp := thing.Struct_thing;
340 Console.WriteLine('testNest({' +
341 IntToStr( thing.Byte_thing) + ', {' +
342 '"' + temp.String_thing + '", ' +
343 IntToStr( temp.Byte_thing) + ', ' +
344 IntToStr( temp.I32_thing) + ', ' +
345 IntToStr( temp.I64_thing) + '}, ' +
346 IntToStr( temp.I32_thing) + '})');
347 Result := thing;
348end;
349
350procedure TTestServer.TTestHandlerImpl.testOneway(secondsToSleep: Integer);
351begin
352 Console.WriteLine('testOneway(' + IntToStr( secondsToSleep )+ '), sleeping...');
353 Sleep(secondsToSleep * 1000);
354 Console.WriteLine('testOneway finished');
355end;
356
357function TTestServer.TTestHandlerImpl.testSet(
Roger Meier333bbf32012-01-08 21:51:08 +0000358 const thing: IHashSet<Integer>):IHashSet<Integer>;
Jake Farrell27274222011-11-10 20:32:44 +0000359var
360 first : Boolean;
361 elem : Integer;
362begin
363 Console.Write('testSet({');
364 first := True;
365
366 for elem in thing do
367 begin
368 if first then
369 begin
370 first := False;
371 end else
372 begin
373 Console.Write( ', ');
374 end;
375 Console.Write( IntToStr( elem));
376 end;
377 Console.WriteLine('})');
378 Result := thing;
379end;
380
381procedure TTestServer.TTestHandlerImpl.testStop;
382begin
383 if FServer <> nil then
384 begin
385 FServer.Stop;
386 end;
387end;
388
Roger Meier333bbf32012-01-08 21:51:08 +0000389function TTestServer.TTestHandlerImpl.testString( const thing: string): string;
Jake Farrell27274222011-11-10 20:32:44 +0000390begin
391 Console.WriteLine('teststring("' + thing + '")');
392 Result := thing;
393end;
394
395function TTestServer.TTestHandlerImpl.testStringMap(
Roger Meier333bbf32012-01-08 21:51:08 +0000396 const thing: IThriftDictionary<string, string>): IThriftDictionary<string, string>;
Roger Meierbb6de7a2012-05-04 23:35:45 +0000397var
398 first : Boolean;
399 key : string;
Jake Farrell27274222011-11-10 20:32:44 +0000400begin
Roger Meierbb6de7a2012-05-04 23:35:45 +0000401 Console.Write('testStringMap({');
402 first := True;
403 for key in thing.Keys do
404 begin
405 if (first) then
406 begin
407 first := false;
408 end else
409 begin
410 Console.Write(', ');
411 end;
412 Console.Write(key + ' => ' + thing[key]);
413 end;
414 Console.WriteLine('})');
415 Result := thing;
Jake Farrell27274222011-11-10 20:32:44 +0000416end;
417
Roger Meier333bbf32012-01-08 21:51:08 +0000418function TTestServer.TTestHandlerImpl.testTypedef( const thing: Int64): Int64;
Jake Farrell27274222011-11-10 20:32:44 +0000419begin
420 Console.WriteLine('testTypedef(' + IntToStr( thing) + ')');
421 Result := thing;
422end;
423
424procedure TTestServer.TTestHandlerImpl.TestVoid;
425begin
426 Console.WriteLine('testVoid()');
427end;
428
Roger Meier333bbf32012-01-08 21:51:08 +0000429function TTestServer.TTestHandlerImpl.testStruct( const thing: IXtruct): IXtruct;
Jake Farrell27274222011-11-10 20:32:44 +0000430begin
431 Console.WriteLine('testStruct({' +
432 '"' + thing.String_thing + '", ' +
433 IntToStr( thing.Byte_thing) + ', ' +
434 IntToStr( thing.I32_thing) + ', ' +
435 IntToStr( thing.I64_thing));
436 Result := thing;
437end;
438
Roger Meier3bef8c22012-10-06 06:58:00 +0000439
Jake Farrell27274222011-11-10 20:32:44 +0000440{ TTestServer }
441
Roger Meier3bef8c22012-10-06 06:58:00 +0000442
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200443class procedure TTestServer.PrintCmdLineHelp;
444const HELPTEXT = ' [options]'#10
445 + #10
446 + 'Allowed options:'#10
447 + ' -h [ --help ] produce help message'#10
448 + ' --port arg (=9090) Port number to listen'#10
449 + ' --domain-socket arg Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)'#10
450 + ' --named-pipe arg Windows Named Pipe (e.g. MyThriftPipe)'#10
451 + ' --server-type arg (=simple) type of server, "simple", "thread-pool",'#10
452 + ' "threaded", or "nonblocking"'#10
453 + ' --transport arg (=socket) transport: buffered, framed, http, anonpipe'#10
454 + ' --protocol arg (=binary) protocol: binary, compact, json'#10
455 + ' --ssl Encrypted Transport using SSL'#10
456 + ' --processor-events processor-events'#10
457 + ' -n [ --workers ] arg (=4) Number of thread pools workers. Only valid for'#10
458 + ' thread-pool server type'#10
459 ;
460begin
461 Console.WriteLine( ChangeFileExt(ExtractFileName(ParamStr(0)),'') + HELPTEXT);
462end;
463
464class procedure TTestServer.InvalidArgs;
465begin
466 Console.WriteLine( 'Invalid args.');
467 Console.WriteLine( ChangeFileExt(ExtractFileName(ParamStr(0)),'') + ' -h for more information');
468 Abort;
469end;
470
Jens Geyer06045cf2013-03-27 20:26:25 +0200471class procedure TTestServer.LaunchAnonPipeChild( const app : string; const transport : IAnonymousPipeServerTransport);
Roger Meier3bef8c22012-10-06 06:58:00 +0000472//Launch child process and pass R/W anonymous pipe handles on cmd line.
473//This is a simple example and does not include elevation or other
474//advanced features.
475var pi : PROCESS_INFORMATION;
Jens Geyerd5436f52014-10-03 19:50:38 +0200476 si : STARTUPINFO;
477 sArg, sHandles, sCmdLine : string;
Roger Meier3bef8c22012-10-06 06:58:00 +0000478 i : Integer;
479begin
480 GetStartupInfo( si); //set startupinfo for the spawned process
481
482 // preformat handles args
483 sHandles := Format( '%d %d',
484 [ Integer(transport.ClientAnonRead),
485 Integer(transport.ClientAnonWrite)]);
486
487 // pass all settings to client
488 sCmdLine := app;
489 for i := 1 to ParamCount do begin
490 sArg := ParamStr(i);
491
492 // add anonymous handles and quote strings where appropriate
493 if sArg = '-anon'
494 then sArg := sArg +' '+ sHandles
495 else begin
496 if Pos(' ',sArg) > 0
497 then sArg := '"'+sArg+'"';
498 end;;
499
500 sCmdLine := sCmdLine +' '+ sArg;
501 end;
502
503 // spawn the child process
504 Console.WriteLine('Starting client '+sCmdLine);
505 Win32Check( CreateProcess( nil, PChar(sCmdLine), nil,nil,TRUE,0,nil,nil,si,pi));
506
507 CloseHandle( pi.hThread);
Jens Geyerd5436f52014-10-03 19:50:38 +0200508 CloseHandle( pi.hProcess);
Roger Meier3bef8c22012-10-06 06:58:00 +0000509end;
510
511
Roger Meier333bbf32012-01-08 21:51:08 +0000512class procedure TTestServer.Execute( const args: array of string);
Jake Farrell27274222011-11-10 20:32:44 +0000513var
Jake Farrell27274222011-11-10 20:32:44 +0000514 Port : Integer;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200515 ServerEvents : Boolean;
Roger Meier3bef8c22012-10-06 06:58:00 +0000516 sPipeName : string;
Jake Farrell27274222011-11-10 20:32:44 +0000517 testHandler : ITestHandler;
518 testProcessor : IProcessor;
Roger Meier3bef8c22012-10-06 06:58:00 +0000519 ServerTrans : IServerTransport;
Jake Farrell27274222011-11-10 20:32:44 +0000520 ServerEngine : IServer;
Jens Geyer06045cf2013-03-27 20:26:25 +0200521 anonymouspipe : IAnonymousPipeServerTransport;
522 namedpipe : INamedPipeServerTransport;
Jake Farrell27274222011-11-10 20:32:44 +0000523 TransportFactory : ITransportFactory;
524 ProtocolFactory : IProtocolFactory;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200525 i, numWorker : Integer;
Jake Farrell27274222011-11-10 20:32:44 +0000526 s : string;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200527 protType : TKnownProtocol;
528 servertype : TServerType;
529 endpoint : TEndpointTransport;
530 layered : TLayeredTransports;
531 UseSSL : Boolean; // include where appropriate (TLayeredTransport?)
Jens Geyer0b20cc82013-03-07 20:47:01 +0100532const
533 // pipe timeouts to be used
534 DEBUG_TIMEOUT = 30 * 1000;
Jens Geyer3e8d9272014-09-14 20:10:40 +0200535 RELEASE_TIMEOUT = DEFAULT_THRIFT_TIMEOUT; // server-side default
Jens Geyer0b20cc82013-03-07 20:47:01 +0100536 TIMEOUT = RELEASE_TIMEOUT;
Jake Farrell27274222011-11-10 20:32:44 +0000537begin
538 try
Jens Geyer01640402013-09-25 21:12:21 +0200539 ServerEvents := FALSE;
Jake Farrell27274222011-11-10 20:32:44 +0000540 protType := prot_Binary;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200541 servertype := srv_Simple;
542 endpoint := trns_Sockets;
543 layered := [];
544 UseSSL := FALSE;
Jake Farrell27274222011-11-10 20:32:44 +0000545 Port := 9090;
Roger Meier3bef8c22012-10-06 06:58:00 +0000546 sPipeName := '';
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200547 numWorker := 4;
Jake Farrell27274222011-11-10 20:32:44 +0000548
549 i := 0;
550 while ( i < Length(args) ) do begin
551 s := args[i];
552 Inc(i);
553
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200554 // Allowed options:
555 if (s = '-h') or (s = '--help') then begin
556 // -h [ --help ] produce help message
557 PrintCmdLineHelp;
558 Exit;
Roger Meier3bef8c22012-10-06 06:58:00 +0000559 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200560 else if (s = '--port') then begin
561 // --port arg (=9090) Port number to listen
562 s := args[i];
563 Inc(i);
564 Port := StrToIntDef( s, Port);
Roger Meier3bef8c22012-10-06 06:58:00 +0000565 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200566 else if (s = '--domain-socket') then begin
567 // --domain-socket arg Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)
568 raise Exception.Create('domain-socket not supported');
Roger Meier3bef8c22012-10-06 06:58:00 +0000569 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200570 else if (s = '--named-pipe') then begin
571 // --named-pipe arg Windows Named Pipe (e.g. MyThriftPipe)
572 endpoint := trns_NamedPipes;
Roger Meier3bef8c22012-10-06 06:58:00 +0000573 sPipeName := args[i]; // -pipe <name>
574 Inc( i );
575 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200576 else if (s = '--server-type') then begin
577 // --server-type arg (=simple) type of server,
578 // arg = "simple", "thread-pool", "threaded", or "nonblocking"
Jake Farrell27274222011-11-10 20:32:44 +0000579 s := args[i];
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200580 Inc(i);
581
582 if s = 'simple' then servertype := srv_Simple
583 else if s = 'thread-pool' then servertype := srv_Threadpool
584 else if s = 'threaded' then servertype := srv_Threaded
585 else if s = 'nonblocking' then servertype := srv_Nonblocking
586 else InvalidArgs;
Jens Geyer01640402013-09-25 21:12:21 +0200587 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200588 else if (s = '--transport') then begin
589 // --transport arg (=buffered) transport: buffered, framed, http
590 s := args[i];
591 Inc(i);
592
593 if s = 'buffered' then Include( layered, trns_Buffered)
594 else if s = 'framed' then Include( layered, trns_Framed)
595 else if s = 'http' then endpoint := trns_Http
596 else if s = 'anonpipe' then endpoint := trns_AnonPipes
597 else InvalidArgs;
598 end
599 else if (s = '--protocol') then begin
600 // --protocol arg (=binary) protocol: binary, compact, json
601 s := args[i];
602 Inc(i);
603
604 if s = 'binary' then protType := prot_Binary
605 else if s = 'compact' then protType := prot_Compact
606 else if s = 'json' then protType := prot_JSON
607 else InvalidArgs;
608 end
609 else if (s = '--ssl') then begin
610 // --ssl Encrypted Transport using SSL
611 UseSSL := TRUE;
612 end
613 else if (s = '--processor-events') then begin
614 // --processor-events processor-events
615 ServerEvents := TRUE;
616 end
617 else if (s = '-n') or (s = '--workers') then begin
618 // -n [ --workers ] arg (=4) Number of thread pools workers.
619 // Only valid for thread-pool server type
620 s := args[i];
621 numWorker := StrToIntDef(s,0);
622 if numWorker > 0
623 then Inc(i)
624 else numWorker := 4;
Jens Geyer01640402013-09-25 21:12:21 +0200625 end
626 else begin
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200627 InvalidArgs;
628 end;
Jake Farrell27274222011-11-10 20:32:44 +0000629 end;
630
Roger Meier3bef8c22012-10-06 06:58:00 +0000631
632 Console.WriteLine('Server configuration: ');
633
Jake Farrell27274222011-11-10 20:32:44 +0000634 // create protocol factory, default to BinaryProtocol
635 case protType of
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200636 prot_Binary : ProtocolFactory := TBinaryProtocolImpl.TFactory.Create( BINARY_STRICT_READ, BINARY_STRICT_WRITE);
637 prot_JSON : ProtocolFactory := TJSONProtocolImpl.TFactory.Create;
638 prot_Compact : raise Exception.Create('Compact protocol not implemented');
Jake Farrell27274222011-11-10 20:32:44 +0000639 else
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200640 raise Exception.Create('Unhandled protocol');
Jake Farrell27274222011-11-10 20:32:44 +0000641 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000642 ASSERT( ProtocolFactory <> nil);
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200643 Console.WriteLine('- '+THRIFT_PROTOCOLS[protType]+' protocol');
Jake Farrell27274222011-11-10 20:32:44 +0000644
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200645 case endpoint of
Jake Farrell27274222011-11-10 20:32:44 +0000646
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200647 trns_Sockets : begin
648 Console.WriteLine('- sockets (port '+IntToStr(port)+')');
649 if (trns_Buffered in layered) then Console.WriteLine('- buffered');
650 servertrans := TServerSocketImpl.Create( Port, 0, (trns_Buffered in layered));
651 end;
652
653 trns_Http : begin
654 raise Exception.Create('HTTP server transport not implemented');
655 end;
656
657 trns_NamedPipes : begin
658 Console.WriteLine('- named pipe ('+sPipeName+')');
659 namedpipe := TNamedPipeServerTransportImpl.Create( sPipeName, 4096, PIPE_UNLIMITED_INSTANCES, TIMEOUT);
660 servertrans := namedpipe;
661 end;
662
663 trns_AnonPipes : begin
664 Console.WriteLine('- anonymous pipes');
665 anonymouspipe := TAnonymousPipeServerTransportImpl.Create;
666 servertrans := anonymouspipe;
667 end
668
669 else
670 raise Exception.Create('Unhandled endpoint transport');
Roger Meier3bef8c22012-10-06 06:58:00 +0000671 end;
672 ASSERT( servertrans <> nil);
673
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200674 if UseSSL then begin
675 raise Exception.Create('SSL not implemented');
676 end;
677
678 if (trns_Framed in layered) then begin
Roger Meier3bef8c22012-10-06 06:58:00 +0000679 Console.WriteLine('- framed transport');
680 TransportFactory := TFramedTransportImpl.TFactory.Create
681 end
682 else begin
683 TransportFactory := TTransportFactoryImpl.Create;
684 end;
685 ASSERT( TransportFactory <> nil);
686
687 testHandler := TTestHandlerImpl.Create;
Jake Farrell27274222011-11-10 20:32:44 +0000688 testProcessor := TThriftTest.TProcessorImpl.Create( testHandler );
Jake Farrell27274222011-11-10 20:32:44 +0000689
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200690 case servertype of
691 srv_Simple : begin
692 ServerEngine := TSimpleServer.Create( testProcessor, ServerTrans, TransportFactory, ProtocolFactory);
693 end;
694
695 srv_Nonblocking : begin
696 raise Exception.Create(SERVER_TYPES[servertype]+' server not implemented');
697 end;
698
699 srv_Threadpool,
700 srv_Threaded: begin
701 if numWorker > 1 then {use here};
702 raise Exception.Create(SERVER_TYPES[servertype]+' server not implemented');
703 end;
704
705 else
706 raise Exception.Create('Unhandled server type');
707 end;
708 ASSERT( ServerEngine <> nil);
Jake Farrell27274222011-11-10 20:32:44 +0000709
710 testHandler.SetServer( ServerEngine);
711
Jens Geyer01640402013-09-25 21:12:21 +0200712 // test events?
713 if ServerEvents then begin
714 Console.WriteLine('- server events test enabled');
715 ServerEngine.ServerEvents := TServerEventsImpl.Create;
716 end;
717
Roger Meier3bef8c22012-10-06 06:58:00 +0000718 // start the client now when we have the anon handles, but before the server starts
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200719 if endpoint = trns_AnonPipes
Roger Meier79655fb2012-10-20 20:59:41 +0000720 then LaunchAnonPipeChild( ExtractFilePath(ParamStr(0))+'client.exe', anonymouspipe);
Jake Farrell27274222011-11-10 20:32:44 +0000721
Jens Geyer06045cf2013-03-27 20:26:25 +0200722 // install Ctrl+C handler before the server starts
723 g_Handler := testHandler;
724 SetConsoleCtrlHandler( @MyConsoleEventHandler, TRUE);
Roger Meier3bef8c22012-10-06 06:58:00 +0000725
726 Console.WriteLine('');
Jens Geyer06045cf2013-03-27 20:26:25 +0200727 repeat
728 Console.WriteLine('Starting the server ...');
729 serverEngine.Serve;
730 until {$IFDEF RunEndless} FALSE {$ELSE} TRUE {$ENDIF};
731
Jake Farrell27274222011-11-10 20:32:44 +0000732 testHandler.SetServer( nil);
Jens Geyer06045cf2013-03-27 20:26:25 +0200733 g_Handler := nil;
Jake Farrell27274222011-11-10 20:32:44 +0000734
735 except
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200736 on E: EAbort do raise;
737 on E: Exception do begin
738 Console.WriteLine( E.Message + #10 + E.StackTrace );
Jake Farrell27274222011-11-10 20:32:44 +0000739 end;
740 end;
741 Console.WriteLine( 'done.');
742end;
743
Jens Geyer06045cf2013-03-27 20:26:25 +0200744
Jake Farrell27274222011-11-10 20:32:44 +0000745end.