blob: bbc798beda1b9952b5264738b0b1bad0cdfba4c1 [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
Jens Geyer9f7f11e2016-04-14 21:37:11 +020022{$I ../src/Thrift.Defines.inc}
Roger Meier3bef8c22012-10-06 06:58:00 +000023{$WARN SYMBOL_PLATFORM OFF}
24
Jens Geyer06045cf2013-03-27 20:26:25 +020025{.$DEFINE RunEndless} // activate to interactively stress-test the server stop routines via Ctrl+C
26
Jake Farrell27274222011-11-10 20:32:44 +000027interface
28
29uses
Roger Meier3bef8c22012-10-06 06:58:00 +000030 Windows, SysUtils,
Jake Farrell27274222011-11-10 20:32:44 +000031 Generics.Collections,
Jake Farrell27274222011-11-10 20:32:44 +000032 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,
Jens Geyera019cda2019-11-09 23:24:52 +010039 Thrift.Configuration,
Jake Farrell27274222011-11-10 20:32:44 +000040 Thrift.Utils,
41 Thrift.Test,
42 Thrift,
43 TestConstants,
Jens Geyer01640402013-09-25 21:12:21 +020044 TestServerEvents,
Jens Geyer3d556242018-01-24 19:14:32 +010045 ConsoleHelper,
Jake Farrell27274222011-11-10 20:32:44 +000046 Contnrs;
47
48type
49 TTestServer = class
50 public
51 type
52
53 ITestHandler = interface( TThriftTest.Iface )
Roger Meier333bbf32012-01-08 21:51:08 +000054 procedure SetServer( const AServer : IServer );
Jens Geyer06045cf2013-03-27 20:26:25 +020055 procedure TestStop;
Jake Farrell27274222011-11-10 20:32:44 +000056 end;
57
58 TTestHandlerImpl = class( TInterfacedObject, ITestHandler )
59 private
60 FServer : IServer;
61 protected
62 procedure testVoid();
Jens Geyer39ba6b72015-09-22 00:00:49 +020063 function testBool(thing: Boolean): Boolean;
Roger Meier333bbf32012-01-08 21:51:08 +000064 function testString(const thing: string): string;
Jake Farrell7ae13e12011-10-18 14:35:26 +000065 function testByte(thing: ShortInt): ShortInt;
66 function testI32(thing: Integer): Integer;
Roger Meier333bbf32012-01-08 21:51:08 +000067 function testI64(const thing: Int64): Int64;
68 function testDouble(const thing: Double): Double;
Jens Geyerfd1b3582014-12-13 23:42:58 +010069 function testBinary(const thing: TBytes): TBytes;
Roger Meier333bbf32012-01-08 21:51:08 +000070 function testStruct(const thing: IXtruct): IXtruct;
71 function testNest(const thing: IXtruct2): IXtruct2;
72 function testMap(const thing: IThriftDictionary<Integer, Integer>): IThriftDictionary<Integer, Integer>;
73 function testStringMap(const thing: IThriftDictionary<string, string>): IThriftDictionary<string, string>;
74 function testSet(const thing: IHashSet<Integer>): IHashSet<Integer>;
75 function testList(const thing: IThriftList<Integer>): IThriftList<Integer>;
Jake Farrell7ae13e12011-10-18 14:35:26 +000076 function testEnum(thing: TNumberz): TNumberz;
Roger Meier333bbf32012-01-08 21:51:08 +000077 function testTypedef(const thing: Int64): Int64;
Jake Farrell7ae13e12011-10-18 14:35:26 +000078 function testMapMap(hello: Integer): IThriftDictionary<Integer, IThriftDictionary<Integer, Integer>>;
Roger Meier333bbf32012-01-08 21:51:08 +000079 function testInsanity(const argument: IInsanity): IThriftDictionary<Int64, IThriftDictionary<TNumberz, IInsanity>>;
80 function testMulti(arg0: ShortInt; arg1: Integer; const arg2: Int64; const arg3: IThriftDictionary<SmallInt, string>; arg4: TNumberz; const arg5: Int64): IXtruct;
81 procedure testException(const arg: string);
82 function testMultiException(const arg0: string; const arg1: string): IXtruct;
Jake Farrell7ae13e12011-10-18 14:35:26 +000083 procedure testOneway(secondsToSleep: Integer);
Jake Farrell27274222011-11-10 20:32:44 +000084
Jens Geyer06045cf2013-03-27 20:26:25 +020085 procedure TestStop;
Roger Meier333bbf32012-01-08 21:51:08 +000086 procedure SetServer( const AServer : IServer );
Jake Farrell27274222011-11-10 20:32:44 +000087 end;
88
Jens Geyerf8a1b7a2014-09-24 00:26:46 +020089 class procedure PrintCmdLineHelp;
90 class procedure InvalidArgs;
91
Jens Geyer06045cf2013-03-27 20:26:25 +020092 class procedure LaunchAnonPipeChild( const app : string; const transport : IAnonymousPipeServerTransport);
Roger Meier333bbf32012-01-08 21:51:08 +000093 class procedure Execute( const args: array of string);
Jake Farrell27274222011-11-10 20:32:44 +000094 end;
95
96implementation
97
Jens Geyer06045cf2013-03-27 20:26:25 +020098
99var g_Handler : TTestServer.ITestHandler = nil;
100
101
102function MyConsoleEventHandler( dwCtrlType : DWORD) : BOOL; stdcall;
103// Note that this Handler procedure is called from another thread
104var handler : TTestServer.ITestHandler;
105begin
106 result := TRUE;
107 try
108 case dwCtrlType of
109 CTRL_C_EVENT : Console.WriteLine( 'Ctrl+C pressed');
110 CTRL_BREAK_EVENT : Console.WriteLine( 'Ctrl+Break pressed');
111 CTRL_CLOSE_EVENT : Console.WriteLine( 'Received CloseTask signal');
112 CTRL_LOGOFF_EVENT : Console.WriteLine( 'Received LogOff signal');
113 CTRL_SHUTDOWN_EVENT : Console.WriteLine( 'Received Shutdown signal');
114 else
115 Console.WriteLine( 'Received console event #'+IntToStr(Integer(dwCtrlType)));
116 end;
117
118 handler := g_Handler;
119 if handler <> nil then handler.TestStop;
120
121 except
122 // catch all
123 end;
124end;
125
126
Jake Farrell27274222011-11-10 20:32:44 +0000127{ TTestServer.TTestHandlerImpl }
128
Roger Meier333bbf32012-01-08 21:51:08 +0000129procedure TTestServer.TTestHandlerImpl.SetServer( const AServer: IServer);
Jake Farrell27274222011-11-10 20:32:44 +0000130begin
131 FServer := AServer;
132end;
133
134function TTestServer.TTestHandlerImpl.testByte(thing: ShortInt): ShortInt;
135begin
136 Console.WriteLine('testByte("' + IntToStr( thing) + '")');
137 Result := thing;
138end;
139
Roger Meier333bbf32012-01-08 21:51:08 +0000140function TTestServer.TTestHandlerImpl.testDouble( const thing: Double): Double;
Jake Farrell27274222011-11-10 20:32:44 +0000141begin
142 Console.WriteLine('testDouble("' + FloatToStr( thing ) + '")');
143 Result := thing;
144end;
145
Jens Geyerfd1b3582014-12-13 23:42:58 +0100146function TTestServer.TTestHandlerImpl.testBinary(const thing: TBytes): TBytes;
147begin
Jens Geyerbd1a2732019-06-26 22:52:44 +0200148 Console.WriteLine('testBinary('+IntToStr(Length(thing)) + ' bytes)');
Jens Geyerfd1b3582014-12-13 23:42:58 +0100149 Result := thing;
150end;
151
Jake Farrell27274222011-11-10 20:32:44 +0000152function TTestServer.TTestHandlerImpl.testEnum(thing: TNumberz): TNumberz;
153begin
Jens Geyer8f7487e2019-05-09 22:21:32 +0200154 Console.WriteLine('testEnum(' + EnumUtils<TNumberz>.ToString(Ord(thing)) + ')');
Jake Farrell27274222011-11-10 20:32:44 +0000155 Result := thing;
156end;
157
Roger Meier333bbf32012-01-08 21:51:08 +0000158procedure TTestServer.TTestHandlerImpl.testException(const arg: string);
Jake Farrell27274222011-11-10 20:32:44 +0000159begin
160 Console.WriteLine('testException(' + arg + ')');
Jens Geyerc140bb92019-11-27 22:18:12 +0100161 if ( arg = 'Xception') then begin
Roger Meierbb6de7a2012-05-04 23:35:45 +0000162 raise TXception.Create( 1001, arg);
Jake Farrell27274222011-11-10 20:32:44 +0000163 end;
Roger Meierbb6de7a2012-05-04 23:35:45 +0000164
Jens Geyerc140bb92019-11-27 22:18:12 +0100165 if (arg = 'TException') then begin
Jens Geyer92d80622018-05-02 22:28:44 +0200166 raise TException.Create('TException');
Roger Meierbb6de7a2012-05-04 23:35:45 +0000167 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
Jake Farrell27274222011-11-10 20:32:44 +0000187 looney : IInsanity;
188 first_map : IThriftDictionary<TNumberz, IInsanity>;
189 second_map : IThriftDictionary<TNumberz, IInsanity>;
190 insane : IThriftDictionary<Int64, IThriftDictionary<TNumberz, IInsanity>>;
191
192begin
Jens Geyer8f7487e2019-05-09 22:21:32 +0200193 Console.Write('testInsanity(');
194 if argument <> nil then Console.Write(argument.ToString);
195 Console.WriteLine(')');
196
Jake Farrell27274222011-11-10 20:32:44 +0000197
Jens Geyer540e3462016-12-28 14:25:41 +0100198 (**
199 * So you think you've got this all worked, out eh?
200 *
201 * Creates a the returned map with these values and prints it out:
202 * { 1 => { 2 => argument,
203 * 3 => argument,
204 * },
205 * 2 => { 6 => <empty Insanity struct>, },
206 * }
207 * @return map<UserId, map<Numberz,Insanity>> - a map with the above values
208 *)
Jake Farrell27274222011-11-10 20:32:44 +0000209
210 first_map := TThriftDictionaryImpl<TNumberz, IInsanity>.Create;
211 second_map := TThriftDictionaryImpl<TNumberz, IInsanity>.Create;
212
Jens Geyer540e3462016-12-28 14:25:41 +0100213 first_map.AddOrSetValue( TNumberz.TWO, argument);
214 first_map.AddOrSetValue( TNumberz.THREE, argument);
Jake Farrell27274222011-11-10 20:32:44 +0000215
Jens Geyer540e3462016-12-28 14:25:41 +0100216 looney := TInsanityImpl.Create;
Jake Farrell27274222011-11-10 20:32:44 +0000217 second_map.AddOrSetValue( TNumberz.SIX, looney);
218
219 insane := TThriftDictionaryImpl<Int64, IThriftDictionary<TNumberz, IInsanity>>.Create;
220
221 insane.AddOrSetValue( 1, first_map);
222 insane.AddOrSetValue( 2, second_map);
223
224 Result := insane;
225end;
226
Jens Geyer8f7487e2019-05-09 22:21:32 +0200227function TTestServer.TTestHandlerImpl.testList( const thing: IThriftList<Integer>): IThriftList<Integer>;
Jake Farrell27274222011-11-10 20:32:44 +0000228begin
Jens Geyer8f7487e2019-05-09 22:21:32 +0200229 Console.Write('testList(');
230 if thing <> nil then Console.Write(thing.ToString);
231 Console.WriteLine(')');
Jake Farrell27274222011-11-10 20:32:44 +0000232 Result := thing;
233end;
234
235function TTestServer.TTestHandlerImpl.testMap(
Roger Meier333bbf32012-01-08 21:51:08 +0000236 const thing: IThriftDictionary<Integer, Integer>): IThriftDictionary<Integer, Integer>;
Jake Farrell27274222011-11-10 20:32:44 +0000237begin
Jens Geyer8f7487e2019-05-09 22:21:32 +0200238 Console.Write('testMap(');
239 if thing <> nil then Console.Write(thing.ToString);
240 Console.WriteLine(')');
Jake Farrell27274222011-11-10 20:32:44 +0000241 Result := thing;
242end;
243
244function TTestServer.TTestHandlerImpl.TestMapMap(
245 hello: Integer): IThriftDictionary<Integer, IThriftDictionary<Integer, Integer>>;
246var
247 mapmap : IThriftDictionary<Integer, IThriftDictionary<Integer, Integer>>;
248 pos : IThriftDictionary<Integer, Integer>;
249 neg : IThriftDictionary<Integer, Integer>;
250 i : Integer;
251begin
252 Console.WriteLine('testMapMap(' + IntToStr( hello) + ')');
253 mapmap := TThriftDictionaryImpl<Integer, IThriftDictionary<Integer, Integer>>.Create;
254 pos := TThriftDictionaryImpl<Integer, Integer>.Create;
255 neg := TThriftDictionaryImpl<Integer, Integer>.Create;
256
257 for i := 1 to 4 do
258 begin
259 pos.AddOrSetValue( i, i);
260 neg.AddOrSetValue( -i, -i);
261 end;
262
263 mapmap.AddOrSetValue(4, pos);
264 mapmap.AddOrSetValue( -4, neg);
265
266 Result := mapmap;
267end;
268
269function TTestServer.TTestHandlerImpl.testMulti(arg0: ShortInt; arg1: Integer;
Roger Meier333bbf32012-01-08 21:51:08 +0000270 const arg2: Int64; const arg3: IThriftDictionary<SmallInt, string>;
271 arg4: TNumberz; const arg5: Int64): IXtruct;
Jake Farrell27274222011-11-10 20:32:44 +0000272var
273 hello : IXtruct;
274begin
275 Console.WriteLine('testMulti()');
276 hello := TXtructImpl.Create;
277 hello.String_thing := 'Hello2';
278 hello.Byte_thing := arg0;
279 hello.I32_thing := arg1;
280 hello.I64_thing := arg2;
281 Result := hello;
282end;
283
Roger Meier333bbf32012-01-08 21:51:08 +0000284function TTestServer.TTestHandlerImpl.testMultiException( const arg0, arg1: string): IXtruct;
Jake Farrell27274222011-11-10 20:32:44 +0000285var
Jake Farrell27274222011-11-10 20:32:44 +0000286 x2 : TXception2;
287begin
288 Console.WriteLine('testMultiException(' + arg0 + ', ' + arg1 + ')');
Jens Geyer8f7487e2019-05-09 22:21:32 +0200289 if ( arg0 = 'Xception') then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200290 raise TXception.Create( 1001, 'This is an Xception'); // test the new rich CTOR
Jens Geyer8f7487e2019-05-09 22:21:32 +0200291 end;
292
293 if ( arg0 = 'Xception2') then begin
Jake Farrell343c61d2011-12-09 02:29:56 +0000294 x2 := TXception2.Create; // the old way still works too?
Jake Farrell27274222011-11-10 20:32:44 +0000295 x2.ErrorCode := 2002;
296 x2.Struct_thing := TXtructImpl.Create;
297 x2.Struct_thing.String_thing := 'This is an Xception2';
Jake Farrellac102562011-11-23 14:30:41 +0000298 x2.UpdateMessageProperty;
Jake Farrell27274222011-11-10 20:32:44 +0000299 raise x2;
300 end;
301
302 Result := TXtructImpl.Create;
303 Result.String_thing := arg1;
304end;
305
Roger Meier333bbf32012-01-08 21:51:08 +0000306function TTestServer.TTestHandlerImpl.testNest( const thing: IXtruct2): IXtruct2;
Jake Farrell27274222011-11-10 20:32:44 +0000307begin
Jens Geyer8f7487e2019-05-09 22:21:32 +0200308 Console.Write('testNest(');
309 if thing <> nil then Console.Write(thing.ToString);
310 Console.WriteLine(')');
311
Jake Farrell27274222011-11-10 20:32:44 +0000312 Result := thing;
313end;
314
315procedure TTestServer.TTestHandlerImpl.testOneway(secondsToSleep: Integer);
316begin
317 Console.WriteLine('testOneway(' + IntToStr( secondsToSleep )+ '), sleeping...');
318 Sleep(secondsToSleep * 1000);
319 Console.WriteLine('testOneway finished');
320end;
321
Jens Geyer8f7487e2019-05-09 22:21:32 +0200322function TTestServer.TTestHandlerImpl.testSet( const thing: IHashSet<Integer>):IHashSet<Integer>;
Jake Farrell27274222011-11-10 20:32:44 +0000323begin
Jens Geyer8f7487e2019-05-09 22:21:32 +0200324 Console.Write('testSet(');
325 if thing <> nil then Console.Write(thing.ToString);
326 Console.WriteLine(')');;
Jake Farrell27274222011-11-10 20:32:44 +0000327
Jake Farrell27274222011-11-10 20:32:44 +0000328 Result := thing;
329end;
330
331procedure TTestServer.TTestHandlerImpl.testStop;
332begin
Jens Geyer8f7487e2019-05-09 22:21:32 +0200333 if FServer <> nil then begin
Jake Farrell27274222011-11-10 20:32:44 +0000334 FServer.Stop;
335 end;
336end;
337
Jens Geyer39ba6b72015-09-22 00:00:49 +0200338function TTestServer.TTestHandlerImpl.testBool(thing: Boolean): Boolean;
339begin
340 Console.WriteLine('testBool(' + BoolToStr(thing,true) + ')');
341 Result := thing;
342end;
343
Roger Meier333bbf32012-01-08 21:51:08 +0000344function TTestServer.TTestHandlerImpl.testString( const thing: string): string;
Jake Farrell27274222011-11-10 20:32:44 +0000345begin
346 Console.WriteLine('teststring("' + thing + '")');
347 Result := thing;
348end;
349
350function TTestServer.TTestHandlerImpl.testStringMap(
Roger Meier333bbf32012-01-08 21:51:08 +0000351 const thing: IThriftDictionary<string, string>): IThriftDictionary<string, string>;
Jake Farrell27274222011-11-10 20:32:44 +0000352begin
Jens Geyer8f7487e2019-05-09 22:21:32 +0200353 Console.Write('testStringMap(');
354 if thing <> nil then Console.Write(thing.ToString);
355 Console.WriteLine(')');
356
Roger Meierbb6de7a2012-05-04 23:35:45 +0000357 Result := thing;
Jake Farrell27274222011-11-10 20:32:44 +0000358end;
359
Roger Meier333bbf32012-01-08 21:51:08 +0000360function TTestServer.TTestHandlerImpl.testTypedef( const thing: Int64): Int64;
Jake Farrell27274222011-11-10 20:32:44 +0000361begin
362 Console.WriteLine('testTypedef(' + IntToStr( thing) + ')');
363 Result := thing;
364end;
365
366procedure TTestServer.TTestHandlerImpl.TestVoid;
367begin
368 Console.WriteLine('testVoid()');
369end;
370
Roger Meier333bbf32012-01-08 21:51:08 +0000371function TTestServer.TTestHandlerImpl.testStruct( const thing: IXtruct): IXtruct;
Jake Farrell27274222011-11-10 20:32:44 +0000372begin
Jens Geyer8f7487e2019-05-09 22:21:32 +0200373 Console.Write('testStruct(');
374 if thing <> nil then Console.Write(thing.ToString);
375 Console.WriteLine(')');
376
Jake Farrell27274222011-11-10 20:32:44 +0000377 Result := thing;
378end;
379
Roger Meier3bef8c22012-10-06 06:58:00 +0000380
Jake Farrell27274222011-11-10 20:32:44 +0000381{ TTestServer }
382
Roger Meier3bef8c22012-10-06 06:58:00 +0000383
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200384class procedure TTestServer.PrintCmdLineHelp;
385const HELPTEXT = ' [options]'#10
386 + #10
387 + 'Allowed options:'#10
388 + ' -h [ --help ] produce help message'#10
389 + ' --port arg (=9090) Port number to listen'#10
390 + ' --domain-socket arg Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)'#10
391 + ' --named-pipe arg Windows Named Pipe (e.g. MyThriftPipe)'#10
392 + ' --server-type arg (=simple) type of server, "simple", "thread-pool",'#10
393 + ' "threaded", or "nonblocking"'#10
394 + ' --transport arg (=socket) transport: buffered, framed, http, anonpipe'#10
395 + ' --protocol arg (=binary) protocol: binary, compact, json'#10
396 + ' --ssl Encrypted Transport using SSL'#10
397 + ' --processor-events processor-events'#10
398 + ' -n [ --workers ] arg (=4) Number of thread pools workers. Only valid for'#10
399 + ' thread-pool server type'#10
400 ;
401begin
402 Console.WriteLine( ChangeFileExt(ExtractFileName(ParamStr(0)),'') + HELPTEXT);
403end;
404
405class procedure TTestServer.InvalidArgs;
406begin
407 Console.WriteLine( 'Invalid args.');
408 Console.WriteLine( ChangeFileExt(ExtractFileName(ParamStr(0)),'') + ' -h for more information');
409 Abort;
410end;
411
Jens Geyer06045cf2013-03-27 20:26:25 +0200412class procedure TTestServer.LaunchAnonPipeChild( const app : string; const transport : IAnonymousPipeServerTransport);
Roger Meier3bef8c22012-10-06 06:58:00 +0000413//Launch child process and pass R/W anonymous pipe handles on cmd line.
414//This is a simple example and does not include elevation or other
415//advanced features.
416var pi : PROCESS_INFORMATION;
Jens Geyerd5436f52014-10-03 19:50:38 +0200417 si : STARTUPINFO;
418 sArg, sHandles, sCmdLine : string;
Roger Meier3bef8c22012-10-06 06:58:00 +0000419 i : Integer;
420begin
421 GetStartupInfo( si); //set startupinfo for the spawned process
422
423 // preformat handles args
424 sHandles := Format( '%d %d',
425 [ Integer(transport.ClientAnonRead),
426 Integer(transport.ClientAnonWrite)]);
427
428 // pass all settings to client
429 sCmdLine := app;
430 for i := 1 to ParamCount do begin
431 sArg := ParamStr(i);
432
433 // add anonymous handles and quote strings where appropriate
434 if sArg = '-anon'
435 then sArg := sArg +' '+ sHandles
436 else begin
437 if Pos(' ',sArg) > 0
438 then sArg := '"'+sArg+'"';
439 end;;
440
441 sCmdLine := sCmdLine +' '+ sArg;
442 end;
443
444 // spawn the child process
445 Console.WriteLine('Starting client '+sCmdLine);
446 Win32Check( CreateProcess( nil, PChar(sCmdLine), nil,nil,TRUE,0,nil,nil,si,pi));
447
448 CloseHandle( pi.hThread);
Jens Geyerd5436f52014-10-03 19:50:38 +0200449 CloseHandle( pi.hProcess);
Roger Meier3bef8c22012-10-06 06:58:00 +0000450end;
451
452
Roger Meier333bbf32012-01-08 21:51:08 +0000453class procedure TTestServer.Execute( const args: array of string);
Jake Farrell27274222011-11-10 20:32:44 +0000454var
Jake Farrell27274222011-11-10 20:32:44 +0000455 Port : Integer;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200456 ServerEvents : Boolean;
Roger Meier3bef8c22012-10-06 06:58:00 +0000457 sPipeName : string;
Jake Farrell27274222011-11-10 20:32:44 +0000458 testHandler : ITestHandler;
459 testProcessor : IProcessor;
Roger Meier3bef8c22012-10-06 06:58:00 +0000460 ServerTrans : IServerTransport;
Jake Farrell27274222011-11-10 20:32:44 +0000461 ServerEngine : IServer;
Jens Geyer06045cf2013-03-27 20:26:25 +0200462 anonymouspipe : IAnonymousPipeServerTransport;
463 namedpipe : INamedPipeServerTransport;
Jake Farrell27274222011-11-10 20:32:44 +0000464 TransportFactory : ITransportFactory;
465 ProtocolFactory : IProtocolFactory;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200466 i, numWorker : Integer;
Jake Farrell27274222011-11-10 20:32:44 +0000467 s : string;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200468 protType : TKnownProtocol;
469 servertype : TServerType;
470 endpoint : TEndpointTransport;
471 layered : TLayeredTransports;
472 UseSSL : Boolean; // include where appropriate (TLayeredTransport?)
Jake Farrell27274222011-11-10 20:32:44 +0000473begin
474 try
Jens Geyer01640402013-09-25 21:12:21 +0200475 ServerEvents := FALSE;
Jake Farrell27274222011-11-10 20:32:44 +0000476 protType := prot_Binary;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200477 servertype := srv_Simple;
478 endpoint := trns_Sockets;
479 layered := [];
480 UseSSL := FALSE;
Jake Farrell27274222011-11-10 20:32:44 +0000481 Port := 9090;
Roger Meier3bef8c22012-10-06 06:58:00 +0000482 sPipeName := '';
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200483 numWorker := 4;
Jake Farrell27274222011-11-10 20:32:44 +0000484
485 i := 0;
486 while ( i < Length(args) ) do begin
487 s := args[i];
488 Inc(i);
489
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200490 // Allowed options:
491 if (s = '-h') or (s = '--help') then begin
492 // -h [ --help ] produce help message
493 PrintCmdLineHelp;
494 Exit;
Roger Meier3bef8c22012-10-06 06:58:00 +0000495 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200496 else if (s = '--port') then begin
497 // --port arg (=9090) Port number to listen
498 s := args[i];
499 Inc(i);
500 Port := StrToIntDef( s, Port);
Roger Meier3bef8c22012-10-06 06:58:00 +0000501 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200502 else if (s = '--domain-socket') then begin
503 // --domain-socket arg Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)
504 raise Exception.Create('domain-socket not supported');
Roger Meier3bef8c22012-10-06 06:58:00 +0000505 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200506 else if (s = '--named-pipe') then begin
507 // --named-pipe arg Windows Named Pipe (e.g. MyThriftPipe)
508 endpoint := trns_NamedPipes;
Roger Meier3bef8c22012-10-06 06:58:00 +0000509 sPipeName := args[i]; // -pipe <name>
510 Inc( i );
511 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200512 else if (s = '--server-type') then begin
513 // --server-type arg (=simple) type of server,
514 // arg = "simple", "thread-pool", "threaded", or "nonblocking"
Jake Farrell27274222011-11-10 20:32:44 +0000515 s := args[i];
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200516 Inc(i);
517
518 if s = 'simple' then servertype := srv_Simple
519 else if s = 'thread-pool' then servertype := srv_Threadpool
520 else if s = 'threaded' then servertype := srv_Threaded
521 else if s = 'nonblocking' then servertype := srv_Nonblocking
522 else InvalidArgs;
Jens Geyer01640402013-09-25 21:12:21 +0200523 end
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200524 else if (s = '--transport') then begin
525 // --transport arg (=buffered) transport: buffered, framed, http
526 s := args[i];
527 Inc(i);
528
529 if s = 'buffered' then Include( layered, trns_Buffered)
530 else if s = 'framed' then Include( layered, trns_Framed)
Jens Geyer02230912019-04-03 01:12:51 +0200531 else if s = 'http' then endpoint := trns_MsxmlHttp
532 else if s = 'winhttp' then endpoint := trns_WinHttp
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200533 else if s = 'anonpipe' then endpoint := trns_AnonPipes
534 else InvalidArgs;
535 end
536 else if (s = '--protocol') then begin
537 // --protocol arg (=binary) protocol: binary, compact, json
538 s := args[i];
539 Inc(i);
540
541 if s = 'binary' then protType := prot_Binary
542 else if s = 'compact' then protType := prot_Compact
543 else if s = 'json' then protType := prot_JSON
544 else InvalidArgs;
545 end
546 else if (s = '--ssl') then begin
547 // --ssl Encrypted Transport using SSL
548 UseSSL := TRUE;
549 end
550 else if (s = '--processor-events') then begin
551 // --processor-events processor-events
552 ServerEvents := TRUE;
553 end
554 else if (s = '-n') or (s = '--workers') then begin
555 // -n [ --workers ] arg (=4) Number of thread pools workers.
556 // Only valid for thread-pool server type
557 s := args[i];
558 numWorker := StrToIntDef(s,0);
559 if numWorker > 0
560 then Inc(i)
561 else numWorker := 4;
Jens Geyer01640402013-09-25 21:12:21 +0200562 end
563 else begin
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200564 InvalidArgs;
565 end;
Jake Farrell27274222011-11-10 20:32:44 +0000566 end;
567
Roger Meier3bef8c22012-10-06 06:58:00 +0000568
569 Console.WriteLine('Server configuration: ');
570
Jake Farrell27274222011-11-10 20:32:44 +0000571 // create protocol factory, default to BinaryProtocol
572 case protType of
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200573 prot_Binary : ProtocolFactory := TBinaryProtocolImpl.TFactory.Create( BINARY_STRICT_READ, BINARY_STRICT_WRITE);
574 prot_JSON : ProtocolFactory := TJSONProtocolImpl.TFactory.Create;
Jens Geyerf0e63312015-03-01 18:47:49 +0100575 prot_Compact : ProtocolFactory := TCompactProtocolImpl.TFactory.Create;
Jake Farrell27274222011-11-10 20:32:44 +0000576 else
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200577 raise Exception.Create('Unhandled protocol');
Jake Farrell27274222011-11-10 20:32:44 +0000578 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000579 ASSERT( ProtocolFactory <> nil);
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200580 Console.WriteLine('- '+THRIFT_PROTOCOLS[protType]+' protocol');
Jake Farrell27274222011-11-10 20:32:44 +0000581
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200582 case endpoint of
Jake Farrell27274222011-11-10 20:32:44 +0000583
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200584 trns_Sockets : begin
585 Console.WriteLine('- sockets (port '+IntToStr(port)+')');
586 if (trns_Buffered in layered) then Console.WriteLine('- buffered');
Jens Geyer41f47af2019-11-09 23:24:52 +0100587 servertrans := TServerSocketImpl.Create( Port, DEFAULT_THRIFT_TIMEOUT, (trns_Buffered in layered));
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200588 end;
589
Jens Geyer02230912019-04-03 01:12:51 +0200590 trns_MsxmlHttp,
591 trns_WinHttp : begin
592 raise Exception.Create('HTTP server transport not implemented');
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200593 end;
594
595 trns_NamedPipes : begin
596 Console.WriteLine('- named pipe ('+sPipeName+')');
Jens Geyera019cda2019-11-09 23:24:52 +0100597 namedpipe := TNamedPipeServerTransportImpl.Create( sPipeName, 4096, PIPE_UNLIMITED_INSTANCES, INFINITE);
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200598 servertrans := namedpipe;
599 end;
600
601 trns_AnonPipes : begin
602 Console.WriteLine('- anonymous pipes');
603 anonymouspipe := TAnonymousPipeServerTransportImpl.Create;
604 servertrans := anonymouspipe;
605 end
606
607 else
608 raise Exception.Create('Unhandled endpoint transport');
Roger Meier3bef8c22012-10-06 06:58:00 +0000609 end;
610 ASSERT( servertrans <> nil);
611
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200612 if UseSSL then begin
613 raise Exception.Create('SSL not implemented');
614 end;
615
616 if (trns_Framed in layered) then begin
Roger Meier3bef8c22012-10-06 06:58:00 +0000617 Console.WriteLine('- framed transport');
Jens Geyera019cda2019-11-09 23:24:52 +0100618 TransportFactory := TFramedTransportImpl.TFactory.Create;
Roger Meier3bef8c22012-10-06 06:58:00 +0000619 end
620 else begin
621 TransportFactory := TTransportFactoryImpl.Create;
622 end;
623 ASSERT( TransportFactory <> nil);
624
625 testHandler := TTestHandlerImpl.Create;
Jake Farrell27274222011-11-10 20:32:44 +0000626 testProcessor := TThriftTest.TProcessorImpl.Create( testHandler );
Jake Farrell27274222011-11-10 20:32:44 +0000627
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200628 case servertype of
629 srv_Simple : begin
630 ServerEngine := TSimpleServer.Create( testProcessor, ServerTrans, TransportFactory, ProtocolFactory);
631 end;
632
633 srv_Nonblocking : begin
634 raise Exception.Create(SERVER_TYPES[servertype]+' server not implemented');
635 end;
636
637 srv_Threadpool,
638 srv_Threaded: begin
639 if numWorker > 1 then {use here};
640 raise Exception.Create(SERVER_TYPES[servertype]+' server not implemented');
641 end;
642
643 else
644 raise Exception.Create('Unhandled server type');
645 end;
646 ASSERT( ServerEngine <> nil);
Jake Farrell27274222011-11-10 20:32:44 +0000647
648 testHandler.SetServer( ServerEngine);
649
Jens Geyer01640402013-09-25 21:12:21 +0200650 // test events?
651 if ServerEvents then begin
652 Console.WriteLine('- server events test enabled');
653 ServerEngine.ServerEvents := TServerEventsImpl.Create;
654 end;
655
Roger Meier3bef8c22012-10-06 06:58:00 +0000656 // start the client now when we have the anon handles, but before the server starts
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200657 if endpoint = trns_AnonPipes
Roger Meier79655fb2012-10-20 20:59:41 +0000658 then LaunchAnonPipeChild( ExtractFilePath(ParamStr(0))+'client.exe', anonymouspipe);
Jake Farrell27274222011-11-10 20:32:44 +0000659
Jens Geyer06045cf2013-03-27 20:26:25 +0200660 // install Ctrl+C handler before the server starts
661 g_Handler := testHandler;
662 SetConsoleCtrlHandler( @MyConsoleEventHandler, TRUE);
Roger Meier3bef8c22012-10-06 06:58:00 +0000663
664 Console.WriteLine('');
Jens Geyer06045cf2013-03-27 20:26:25 +0200665 repeat
666 Console.WriteLine('Starting the server ...');
667 serverEngine.Serve;
668 until {$IFDEF RunEndless} FALSE {$ELSE} TRUE {$ENDIF};
669
Jake Farrell27274222011-11-10 20:32:44 +0000670 testHandler.SetServer( nil);
Jens Geyer06045cf2013-03-27 20:26:25 +0200671 g_Handler := nil;
Jake Farrell27274222011-11-10 20:32:44 +0000672
673 except
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200674 on E: EAbort do raise;
675 on E: Exception do begin
676 Console.WriteLine( E.Message + #10 + E.StackTrace );
Jake Farrell27274222011-11-10 20:32:44 +0000677 end;
678 end;
679 Console.WriteLine( 'done.');
680end;
681
Jens Geyer06045cf2013-03-27 20:26:25 +0200682
Jake Farrell27274222011-11-10 20:32:44 +0000683end.