blob: 1e3a3938d5d10b95bb6504bd972874b7e6074b16 [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
Jens Geyer0eab6e02023-11-03 11:17:01 +010058 TTestHandlerImpl = class( TInterfacedObject, ITestHandler, TThriftTest.Iface)
Jens Geyeraeda9872020-03-22 15:01:28 +010059 strict private
Jake Farrell27274222011-11-10 20:32:44 +000060 FServer : IServer;
Jens Geyeraeda9872020-03-22 15:01:28 +010061 strict protected
Jake Farrell27274222011-11-10 20:32:44 +000062 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;
Jens Geyer62445c12022-06-29 00:00:00 +020070 function testUuid(const thing: System.TGuid): System.TGuid;
Roger Meier333bbf32012-01-08 21:51:08 +000071 function testStruct(const thing: IXtruct): IXtruct;
72 function testNest(const thing: IXtruct2): IXtruct2;
73 function testMap(const thing: IThriftDictionary<Integer, Integer>): IThriftDictionary<Integer, Integer>;
74 function testStringMap(const thing: IThriftDictionary<string, string>): IThriftDictionary<string, string>;
Jens Geyer6a797b92022-09-05 13:55:37 +020075 function testSet(const thing: IThriftHashSet<Integer>): IThriftHashSet<Integer>;
Roger Meier333bbf32012-01-08 21:51:08 +000076 function testList(const thing: IThriftList<Integer>): IThriftList<Integer>;
Jake Farrell7ae13e12011-10-18 14:35:26 +000077 function testEnum(thing: TNumberz): TNumberz;
Roger Meier333bbf32012-01-08 21:51:08 +000078 function testTypedef(const thing: Int64): Int64;
Jake Farrell7ae13e12011-10-18 14:35:26 +000079 function testMapMap(hello: Integer): IThriftDictionary<Integer, IThriftDictionary<Integer, Integer>>;
Roger Meier333bbf32012-01-08 21:51:08 +000080 function testInsanity(const argument: IInsanity): IThriftDictionary<Int64, IThriftDictionary<TNumberz, IInsanity>>;
81 function testMulti(arg0: ShortInt; arg1: Integer; const arg2: Int64; const arg3: IThriftDictionary<SmallInt, string>; arg4: TNumberz; const arg5: Int64): IXtruct;
82 procedure testException(const arg: string);
83 function testMultiException(const arg0: string; const arg1: string): IXtruct;
Jake Farrell7ae13e12011-10-18 14:35:26 +000084 procedure testOneway(secondsToSleep: Integer);
Jake Farrell27274222011-11-10 20:32:44 +000085
Jens Geyer06045cf2013-03-27 20:26:25 +020086 procedure TestStop;
Roger Meier333bbf32012-01-08 21:51:08 +000087 procedure SetServer( const AServer : IServer );
Jake Farrell27274222011-11-10 20:32:44 +000088 end;
89
Jens Geyerf8a1b7a2014-09-24 00:26:46 +020090 class procedure PrintCmdLineHelp;
91 class procedure InvalidArgs;
Jens Geyeraeda9872020-03-22 15:01:28 +010092 class function IsSwitch( const aArgument, aSwitch : string; out sValue : string) : Boolean;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +020093
Jens Geyer06045cf2013-03-27 20:26:25 +020094 class procedure LaunchAnonPipeChild( const app : string; const transport : IAnonymousPipeServerTransport);
Jens Geyeraeda9872020-03-22 15:01:28 +010095 class procedure Execute( const arguments : array of string);
Jake Farrell27274222011-11-10 20:32:44 +000096 end;
97
98implementation
99
Jens Geyer06045cf2013-03-27 20:26:25 +0200100
101var g_Handler : TTestServer.ITestHandler = nil;
102
103
104function MyConsoleEventHandler( dwCtrlType : DWORD) : BOOL; stdcall;
105// Note that this Handler procedure is called from another thread
106var handler : TTestServer.ITestHandler;
107begin
108 result := TRUE;
109 try
110 case dwCtrlType of
111 CTRL_C_EVENT : Console.WriteLine( 'Ctrl+C pressed');
112 CTRL_BREAK_EVENT : Console.WriteLine( 'Ctrl+Break pressed');
113 CTRL_CLOSE_EVENT : Console.WriteLine( 'Received CloseTask signal');
114 CTRL_LOGOFF_EVENT : Console.WriteLine( 'Received LogOff signal');
115 CTRL_SHUTDOWN_EVENT : Console.WriteLine( 'Received Shutdown signal');
116 else
117 Console.WriteLine( 'Received console event #'+IntToStr(Integer(dwCtrlType)));
118 end;
119
120 handler := g_Handler;
121 if handler <> nil then handler.TestStop;
122
123 except
124 // catch all
125 end;
126end;
127
128
Jake Farrell27274222011-11-10 20:32:44 +0000129{ TTestServer.TTestHandlerImpl }
130
Roger Meier333bbf32012-01-08 21:51:08 +0000131procedure TTestServer.TTestHandlerImpl.SetServer( const AServer: IServer);
Jake Farrell27274222011-11-10 20:32:44 +0000132begin
133 FServer := AServer;
134end;
135
136function TTestServer.TTestHandlerImpl.testByte(thing: ShortInt): ShortInt;
137begin
138 Console.WriteLine('testByte("' + IntToStr( thing) + '")');
139 Result := thing;
140end;
141
Roger Meier333bbf32012-01-08 21:51:08 +0000142function TTestServer.TTestHandlerImpl.testDouble( const thing: Double): Double;
Jake Farrell27274222011-11-10 20:32:44 +0000143begin
144 Console.WriteLine('testDouble("' + FloatToStr( thing ) + '")');
145 Result := thing;
146end;
147
Jens Geyerfd1b3582014-12-13 23:42:58 +0100148function TTestServer.TTestHandlerImpl.testBinary(const thing: TBytes): TBytes;
149begin
Jens Geyerbd1a2732019-06-26 22:52:44 +0200150 Console.WriteLine('testBinary('+IntToStr(Length(thing)) + ' bytes)');
Jens Geyerfd1b3582014-12-13 23:42:58 +0100151 Result := thing;
152end;
153
Jens Geyer62445c12022-06-29 00:00:00 +0200154function TTestServer.TTestHandlerImpl.testUuid(const thing: System.TGuid): System.TGuid;
155begin
156 Console.WriteLine('testUuid('+GUIDToString(thing)+')');
157 Result := thing;
158end;
159
Jake Farrell27274222011-11-10 20:32:44 +0000160function TTestServer.TTestHandlerImpl.testEnum(thing: TNumberz): TNumberz;
161begin
Jens Geyer8f7487e2019-05-09 22:21:32 +0200162 Console.WriteLine('testEnum(' + EnumUtils<TNumberz>.ToString(Ord(thing)) + ')');
Jake Farrell27274222011-11-10 20:32:44 +0000163 Result := thing;
164end;
165
Roger Meier333bbf32012-01-08 21:51:08 +0000166procedure TTestServer.TTestHandlerImpl.testException(const arg: string);
Jake Farrell27274222011-11-10 20:32:44 +0000167begin
168 Console.WriteLine('testException(' + arg + ')');
Jens Geyerc140bb92019-11-27 22:18:12 +0100169 if ( arg = 'Xception') then begin
Roger Meierbb6de7a2012-05-04 23:35:45 +0000170 raise TXception.Create( 1001, arg);
Jake Farrell27274222011-11-10 20:32:44 +0000171 end;
Roger Meierbb6de7a2012-05-04 23:35:45 +0000172
Jens Geyerc140bb92019-11-27 22:18:12 +0100173 if (arg = 'TException') then begin
Jens Geyer92d80622018-05-02 22:28:44 +0200174 raise TException.Create('TException');
Roger Meierbb6de7a2012-05-04 23:35:45 +0000175 end;
176
177 // else do not throw anything
Jake Farrell27274222011-11-10 20:32:44 +0000178end;
179
180function TTestServer.TTestHandlerImpl.testI32(thing: Integer): Integer;
181begin
182 Console.WriteLine('testI32("' + IntToStr( thing) + '")');
183 Result := thing;
184end;
185
Roger Meier333bbf32012-01-08 21:51:08 +0000186function TTestServer.TTestHandlerImpl.testI64( const thing: Int64): Int64;
Jake Farrell27274222011-11-10 20:32:44 +0000187begin
188 Console.WriteLine('testI64("' + IntToStr( thing) + '")');
189 Result := thing;
190end;
191
192function TTestServer.TTestHandlerImpl.testInsanity(
Roger Meier333bbf32012-01-08 21:51:08 +0000193 const argument: IInsanity): IThriftDictionary<Int64, IThriftDictionary<TNumberz, IInsanity>>;
Jake Farrell27274222011-11-10 20:32:44 +0000194var
Jake Farrell27274222011-11-10 20:32:44 +0000195 looney : IInsanity;
196 first_map : IThriftDictionary<TNumberz, IInsanity>;
197 second_map : IThriftDictionary<TNumberz, IInsanity>;
198 insane : IThriftDictionary<Int64, IThriftDictionary<TNumberz, IInsanity>>;
199
200begin
Jens Geyer8f7487e2019-05-09 22:21:32 +0200201 Console.Write('testInsanity(');
202 if argument <> nil then Console.Write(argument.ToString);
203 Console.WriteLine(')');
204
Jake Farrell27274222011-11-10 20:32:44 +0000205
Jens Geyer540e3462016-12-28 14:25:41 +0100206 (**
207 * So you think you've got this all worked, out eh?
208 *
209 * Creates a the returned map with these values and prints it out:
210 * { 1 => { 2 => argument,
211 * 3 => argument,
212 * },
213 * 2 => { 6 => <empty Insanity struct>, },
214 * }
215 * @return map<UserId, map<Numberz,Insanity>> - a map with the above values
216 *)
Jake Farrell27274222011-11-10 20:32:44 +0000217
218 first_map := TThriftDictionaryImpl<TNumberz, IInsanity>.Create;
219 second_map := TThriftDictionaryImpl<TNumberz, IInsanity>.Create;
220
Jens Geyer540e3462016-12-28 14:25:41 +0100221 first_map.AddOrSetValue( TNumberz.TWO, argument);
222 first_map.AddOrSetValue( TNumberz.THREE, argument);
Jake Farrell27274222011-11-10 20:32:44 +0000223
Jens Geyer540e3462016-12-28 14:25:41 +0100224 looney := TInsanityImpl.Create;
Jake Farrell27274222011-11-10 20:32:44 +0000225 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
Jens Geyer8f7487e2019-05-09 22:21:32 +0200235function TTestServer.TTestHandlerImpl.testList( const thing: IThriftList<Integer>): IThriftList<Integer>;
Jake Farrell27274222011-11-10 20:32:44 +0000236begin
Jens Geyer8f7487e2019-05-09 22:21:32 +0200237 Console.Write('testList(');
238 if thing <> nil then Console.Write(thing.ToString);
239 Console.WriteLine(')');
Jake Farrell27274222011-11-10 20:32:44 +0000240 Result := thing;
241end;
242
243function TTestServer.TTestHandlerImpl.testMap(
Roger Meier333bbf32012-01-08 21:51:08 +0000244 const thing: IThriftDictionary<Integer, Integer>): IThriftDictionary<Integer, Integer>;
Jake Farrell27274222011-11-10 20:32:44 +0000245begin
Jens Geyer8f7487e2019-05-09 22:21:32 +0200246 Console.Write('testMap(');
247 if thing <> nil then Console.Write(thing.ToString);
248 Console.WriteLine(')');
Jake Farrell27274222011-11-10 20:32:44 +0000249 Result := thing;
250end;
251
252function TTestServer.TTestHandlerImpl.TestMapMap(
253 hello: Integer): IThriftDictionary<Integer, IThriftDictionary<Integer, Integer>>;
254var
255 mapmap : IThriftDictionary<Integer, IThriftDictionary<Integer, Integer>>;
256 pos : IThriftDictionary<Integer, Integer>;
257 neg : IThriftDictionary<Integer, Integer>;
258 i : Integer;
259begin
260 Console.WriteLine('testMapMap(' + IntToStr( hello) + ')');
261 mapmap := TThriftDictionaryImpl<Integer, IThriftDictionary<Integer, Integer>>.Create;
262 pos := TThriftDictionaryImpl<Integer, Integer>.Create;
263 neg := TThriftDictionaryImpl<Integer, Integer>.Create;
264
265 for i := 1 to 4 do
266 begin
267 pos.AddOrSetValue( i, i);
268 neg.AddOrSetValue( -i, -i);
269 end;
270
271 mapmap.AddOrSetValue(4, pos);
272 mapmap.AddOrSetValue( -4, neg);
273
274 Result := mapmap;
275end;
276
277function TTestServer.TTestHandlerImpl.testMulti(arg0: ShortInt; arg1: Integer;
Roger Meier333bbf32012-01-08 21:51:08 +0000278 const arg2: Int64; const arg3: IThriftDictionary<SmallInt, string>;
279 arg4: TNumberz; const arg5: Int64): IXtruct;
Jake Farrell27274222011-11-10 20:32:44 +0000280var
281 hello : IXtruct;
282begin
283 Console.WriteLine('testMulti()');
284 hello := TXtructImpl.Create;
285 hello.String_thing := 'Hello2';
286 hello.Byte_thing := arg0;
287 hello.I32_thing := arg1;
288 hello.I64_thing := arg2;
289 Result := hello;
290end;
291
Roger Meier333bbf32012-01-08 21:51:08 +0000292function TTestServer.TTestHandlerImpl.testMultiException( const arg0, arg1: string): IXtruct;
Jake Farrell27274222011-11-10 20:32:44 +0000293var
Jake Farrell27274222011-11-10 20:32:44 +0000294 x2 : TXception2;
295begin
296 Console.WriteLine('testMultiException(' + arg0 + ', ' + arg1 + ')');
Jens Geyer8f7487e2019-05-09 22:21:32 +0200297 if ( arg0 = 'Xception') then begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200298 raise TXception.Create( 1001, 'This is an Xception'); // test the new rich CTOR
Jens Geyer8f7487e2019-05-09 22:21:32 +0200299 end;
300
301 if ( arg0 = 'Xception2') then begin
Jake Farrell343c61d2011-12-09 02:29:56 +0000302 x2 := TXception2.Create; // the old way still works too?
Jake Farrell27274222011-11-10 20:32:44 +0000303 x2.ErrorCode := 2002;
304 x2.Struct_thing := TXtructImpl.Create;
305 x2.Struct_thing.String_thing := 'This is an Xception2';
Jake Farrellac102562011-11-23 14:30:41 +0000306 x2.UpdateMessageProperty;
Jake Farrell27274222011-11-10 20:32:44 +0000307 raise x2;
308 end;
309
310 Result := TXtructImpl.Create;
311 Result.String_thing := arg1;
312end;
313
Roger Meier333bbf32012-01-08 21:51:08 +0000314function TTestServer.TTestHandlerImpl.testNest( const thing: IXtruct2): IXtruct2;
Jake Farrell27274222011-11-10 20:32:44 +0000315begin
Jens Geyer8f7487e2019-05-09 22:21:32 +0200316 Console.Write('testNest(');
317 if thing <> nil then Console.Write(thing.ToString);
318 Console.WriteLine(')');
319
Jake Farrell27274222011-11-10 20:32:44 +0000320 Result := thing;
321end;
322
323procedure TTestServer.TTestHandlerImpl.testOneway(secondsToSleep: Integer);
324begin
325 Console.WriteLine('testOneway(' + IntToStr( secondsToSleep )+ '), sleeping...');
326 Sleep(secondsToSleep * 1000);
327 Console.WriteLine('testOneway finished');
328end;
329
Jens Geyer6a797b92022-09-05 13:55:37 +0200330function TTestServer.TTestHandlerImpl.testSet( const thing: IThriftHashSet<Integer>):IThriftHashSet<Integer>;
Jake Farrell27274222011-11-10 20:32:44 +0000331begin
Jens Geyer8f7487e2019-05-09 22:21:32 +0200332 Console.Write('testSet(');
333 if thing <> nil then Console.Write(thing.ToString);
334 Console.WriteLine(')');;
Jake Farrell27274222011-11-10 20:32:44 +0000335
Jake Farrell27274222011-11-10 20:32:44 +0000336 Result := thing;
337end;
338
339procedure TTestServer.TTestHandlerImpl.testStop;
340begin
Jens Geyer8f7487e2019-05-09 22:21:32 +0200341 if FServer <> nil then begin
Jake Farrell27274222011-11-10 20:32:44 +0000342 FServer.Stop;
343 end;
344end;
345
Jens Geyer39ba6b72015-09-22 00:00:49 +0200346function TTestServer.TTestHandlerImpl.testBool(thing: Boolean): Boolean;
347begin
348 Console.WriteLine('testBool(' + BoolToStr(thing,true) + ')');
349 Result := thing;
350end;
351
Roger Meier333bbf32012-01-08 21:51:08 +0000352function TTestServer.TTestHandlerImpl.testString( const thing: string): string;
Jake Farrell27274222011-11-10 20:32:44 +0000353begin
354 Console.WriteLine('teststring("' + thing + '")');
355 Result := thing;
356end;
357
358function TTestServer.TTestHandlerImpl.testStringMap(
Roger Meier333bbf32012-01-08 21:51:08 +0000359 const thing: IThriftDictionary<string, string>): IThriftDictionary<string, string>;
Jake Farrell27274222011-11-10 20:32:44 +0000360begin
Jens Geyer8f7487e2019-05-09 22:21:32 +0200361 Console.Write('testStringMap(');
362 if thing <> nil then Console.Write(thing.ToString);
363 Console.WriteLine(')');
364
Roger Meierbb6de7a2012-05-04 23:35:45 +0000365 Result := thing;
Jake Farrell27274222011-11-10 20:32:44 +0000366end;
367
Roger Meier333bbf32012-01-08 21:51:08 +0000368function TTestServer.TTestHandlerImpl.testTypedef( const thing: Int64): Int64;
Jake Farrell27274222011-11-10 20:32:44 +0000369begin
370 Console.WriteLine('testTypedef(' + IntToStr( thing) + ')');
371 Result := thing;
372end;
373
374procedure TTestServer.TTestHandlerImpl.TestVoid;
375begin
376 Console.WriteLine('testVoid()');
377end;
378
Roger Meier333bbf32012-01-08 21:51:08 +0000379function TTestServer.TTestHandlerImpl.testStruct( const thing: IXtruct): IXtruct;
Jake Farrell27274222011-11-10 20:32:44 +0000380begin
Jens Geyer8f7487e2019-05-09 22:21:32 +0200381 Console.Write('testStruct(');
382 if thing <> nil then Console.Write(thing.ToString);
383 Console.WriteLine(')');
384
Jake Farrell27274222011-11-10 20:32:44 +0000385 Result := thing;
386end;
387
Roger Meier3bef8c22012-10-06 06:58:00 +0000388
Jake Farrell27274222011-11-10 20:32:44 +0000389{ TTestServer }
390
Roger Meier3bef8c22012-10-06 06:58:00 +0000391
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200392class procedure TTestServer.PrintCmdLineHelp;
393const HELPTEXT = ' [options]'#10
394 + #10
395 + 'Allowed options:'#10
Jens Geyeraeda9872020-03-22 15:01:28 +0100396 + ' -h | --help Produces this help message'#10
397 + ' --port=arg (9090) Port number to connect'#10
398 + ' --pipe=arg Windows Named Pipe (e.g. MyThriftPipe)'#10
399 + ' --anon-pipes Windows Anonymous Pipes server, auto-starts client.exe'#10
400 + ' --server-type=arg (simple) Type of server (simple, thread-pool, threaded, nonblocking)'#10
401 + ' --transport=arg (sockets) Transport: buffered, framed, anonpipe'#10
402 + ' --protocol=arg (binary) Protocol: binary, compact, json'#10
403 + ' --ssl Encrypted Transport using SSL'#10
404 + ' --processor-events Enable processor-events'#10
405 + ' -n=num | --workers=num (4) Number of thread-pool server workers'#10
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200406 ;
407begin
408 Console.WriteLine( ChangeFileExt(ExtractFileName(ParamStr(0)),'') + HELPTEXT);
409end;
410
411class procedure TTestServer.InvalidArgs;
412begin
413 Console.WriteLine( 'Invalid args.');
414 Console.WriteLine( ChangeFileExt(ExtractFileName(ParamStr(0)),'') + ' -h for more information');
415 Abort;
416end;
417
Jens Geyeraeda9872020-03-22 15:01:28 +0100418class function TTestServer.IsSwitch( const aArgument, aSwitch : string; out sValue : string) : Boolean;
419begin
420 sValue := '';
421 result := (Copy( aArgument, 1, Length(aSwitch)) = aSwitch);
422 if result then begin
423 if (Copy( aArgument, 1, Length(aSwitch)+1) = (aSwitch+'='))
424 then sValue := Copy( aArgument, Length(aSwitch)+2, MAXINT);
425 end;
426end;
427
Jens Geyer06045cf2013-03-27 20:26:25 +0200428class procedure TTestServer.LaunchAnonPipeChild( const app : string; const transport : IAnonymousPipeServerTransport);
Roger Meier3bef8c22012-10-06 06:58:00 +0000429//Launch child process and pass R/W anonymous pipe handles on cmd line.
430//This is a simple example and does not include elevation or other
431//advanced features.
432var pi : PROCESS_INFORMATION;
Jens Geyerd5436f52014-10-03 19:50:38 +0200433 si : STARTUPINFO;
434 sArg, sHandles, sCmdLine : string;
Roger Meier3bef8c22012-10-06 06:58:00 +0000435 i : Integer;
436begin
437 GetStartupInfo( si); //set startupinfo for the spawned process
438
439 // preformat handles args
440 sHandles := Format( '%d %d',
441 [ Integer(transport.ClientAnonRead),
442 Integer(transport.ClientAnonWrite)]);
443
444 // pass all settings to client
445 sCmdLine := app;
446 for i := 1 to ParamCount do begin
447 sArg := ParamStr(i);
448
449 // add anonymous handles and quote strings where appropriate
Jens Geyeraeda9872020-03-22 15:01:28 +0100450 if sArg = '--anon-pipes'
Roger Meier3bef8c22012-10-06 06:58:00 +0000451 then sArg := sArg +' '+ sHandles
452 else begin
453 if Pos(' ',sArg) > 0
454 then sArg := '"'+sArg+'"';
455 end;;
456
457 sCmdLine := sCmdLine +' '+ sArg;
458 end;
459
460 // spawn the child process
461 Console.WriteLine('Starting client '+sCmdLine);
462 Win32Check( CreateProcess( nil, PChar(sCmdLine), nil,nil,TRUE,0,nil,nil,si,pi));
463
464 CloseHandle( pi.hThread);
Jens Geyeraeda9872020-03-22 15:01:28 +0100465 CloseHandle( pi.hProcess);
Roger Meier3bef8c22012-10-06 06:58:00 +0000466end;
467
468
Jens Geyeraeda9872020-03-22 15:01:28 +0100469class procedure TTestServer.Execute( const arguments : array of string);
Jake Farrell27274222011-11-10 20:32:44 +0000470var
Jake Farrell27274222011-11-10 20:32:44 +0000471 Port : Integer;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200472 ServerEvents : Boolean;
Roger Meier3bef8c22012-10-06 06:58:00 +0000473 sPipeName : string;
Jake Farrell27274222011-11-10 20:32:44 +0000474 testHandler : ITestHandler;
475 testProcessor : IProcessor;
Roger Meier3bef8c22012-10-06 06:58:00 +0000476 ServerTrans : IServerTransport;
Jake Farrell27274222011-11-10 20:32:44 +0000477 ServerEngine : IServer;
Jens Geyer06045cf2013-03-27 20:26:25 +0200478 anonymouspipe : IAnonymousPipeServerTransport;
479 namedpipe : INamedPipeServerTransport;
Jake Farrell27274222011-11-10 20:32:44 +0000480 TransportFactory : ITransportFactory;
481 ProtocolFactory : IProtocolFactory;
Jens Geyeraeda9872020-03-22 15:01:28 +0100482 iArg, numWorker : Integer;
483 sArg, sValue : string;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200484 protType : TKnownProtocol;
485 servertype : TServerType;
486 endpoint : TEndpointTransport;
487 layered : TLayeredTransports;
488 UseSSL : Boolean; // include where appropriate (TLayeredTransport?)
Jens Geyer20a86d62021-04-02 11:34:08 +0200489 config : IThriftConfiguration;
490const
491 PIPEFLAGS = [ TNamedPipeFlag.OnlyLocalClients];
Jake Farrell27274222011-11-10 20:32:44 +0000492begin
493 try
Jens Geyer01640402013-09-25 21:12:21 +0200494 ServerEvents := FALSE;
Jake Farrell27274222011-11-10 20:32:44 +0000495 protType := prot_Binary;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200496 servertype := srv_Simple;
497 endpoint := trns_Sockets;
498 layered := [];
499 UseSSL := FALSE;
Jake Farrell27274222011-11-10 20:32:44 +0000500 Port := 9090;
Roger Meier3bef8c22012-10-06 06:58:00 +0000501 sPipeName := '';
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200502 numWorker := 4;
Jake Farrell27274222011-11-10 20:32:44 +0000503
Jens Geyeraeda9872020-03-22 15:01:28 +0100504 iArg := 0;
505 while iArg < Length(arguments) do begin
506 sArg := arguments[iArg];
507 Inc(iArg);
Jake Farrell27274222011-11-10 20:32:44 +0000508
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200509 // Allowed options:
Jens Geyeraeda9872020-03-22 15:01:28 +0100510 if IsSwitch( sArg, '-h', sValue)
511 or IsSwitch( sArg, '--help', sValue)
512 then begin
513 // -h | --help produce help message
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200514 PrintCmdLineHelp;
515 Exit;
Roger Meier3bef8c22012-10-06 06:58:00 +0000516 end
Jens Geyeraeda9872020-03-22 15:01:28 +0100517 else if IsSwitch( sArg, '--port', sValue) then begin
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200518 // --port arg (=9090) Port number to listen
Jens Geyeraeda9872020-03-22 15:01:28 +0100519 Port := StrToIntDef( sValue, Port);
Roger Meier3bef8c22012-10-06 06:58:00 +0000520 end
Jens Geyeraeda9872020-03-22 15:01:28 +0100521 else if IsSwitch( sArg, '--anon-pipes', sValue) then begin
522 endpoint := trns_AnonPipes;
Roger Meier3bef8c22012-10-06 06:58:00 +0000523 end
Jens Geyeraeda9872020-03-22 15:01:28 +0100524 else if IsSwitch( sArg, '--pipe', sValue) then begin
Jens Geyer4a33b182020-03-22 13:46:34 +0100525 // --pipe arg Windows Named Pipe (e.g. MyThriftPipe)
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200526 endpoint := trns_NamedPipes;
Jens Geyeraeda9872020-03-22 15:01:28 +0100527 sPipeName := sValue; // --pipe <name>
Roger Meier3bef8c22012-10-06 06:58:00 +0000528 end
Jens Geyeraeda9872020-03-22 15:01:28 +0100529 else if IsSwitch( sArg, '--server-type', sValue) then begin
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200530 // --server-type arg (=simple) type of server,
531 // arg = "simple", "thread-pool", "threaded", or "nonblocking"
Jens Geyeraeda9872020-03-22 15:01:28 +0100532 if sValue = 'simple' then servertype := srv_Simple
533 else if sValue = 'thread-pool' then servertype := srv_Threadpool
534 else if sValue = 'threaded' then servertype := srv_Threaded
535 else if sValue = 'nonblocking' then servertype := srv_Nonblocking
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200536 else InvalidArgs;
Jens Geyer01640402013-09-25 21:12:21 +0200537 end
Jens Geyeraeda9872020-03-22 15:01:28 +0100538 else if IsSwitch( sArg, '--transport', sValue) then begin
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200539 // --transport arg (=buffered) transport: buffered, framed, http
Jens Geyeraeda9872020-03-22 15:01:28 +0100540 if sValue = 'buffered' then Include( layered, trns_Buffered)
541 else if sValue = 'framed' then Include( layered, trns_Framed)
542 else if sValue = 'http' then endpoint := trns_MsxmlHttp
543 else if sValue = 'winhttp' then endpoint := trns_WinHttp
544 else if sValue = 'anonpipe' then endpoint := trns_AnonPipes
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200545 else InvalidArgs;
546 end
Jens Geyeraeda9872020-03-22 15:01:28 +0100547 else if IsSwitch( sArg, '--protocol', sValue) then begin
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200548 // --protocol arg (=binary) protocol: binary, compact, json
Jens Geyeraeda9872020-03-22 15:01:28 +0100549 if sValue = 'binary' then protType := prot_Binary
550 else if sValue = 'compact' then protType := prot_Compact
551 else if sValue = 'json' then protType := prot_JSON
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200552 else InvalidArgs;
553 end
Jens Geyeraeda9872020-03-22 15:01:28 +0100554 else if IsSwitch( sArg, '--ssl', sValue) then begin
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200555 // --ssl Encrypted Transport using SSL
556 UseSSL := TRUE;
557 end
Jens Geyeraeda9872020-03-22 15:01:28 +0100558 else if IsSwitch( sArg, '--processor-events', sValue) then begin
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200559 // --processor-events processor-events
560 ServerEvents := TRUE;
561 end
Jens Geyeraeda9872020-03-22 15:01:28 +0100562 else if IsSwitch( sArg, '-n', sValue) or IsSwitch( sArg, '--workers', sValue) then begin
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200563 // -n [ --workers ] arg (=4) Number of thread pools workers.
564 // Only valid for thread-pool server type
Jens Geyeraeda9872020-03-22 15:01:28 +0100565 numWorker := StrToIntDef(sValue,4);
Jens Geyer01640402013-09-25 21:12:21 +0200566 end
567 else begin
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200568 InvalidArgs;
569 end;
Jake Farrell27274222011-11-10 20:32:44 +0000570 end;
571
Roger Meier3bef8c22012-10-06 06:58:00 +0000572
573 Console.WriteLine('Server configuration: ');
574
Jake Farrell27274222011-11-10 20:32:44 +0000575 // create protocol factory, default to BinaryProtocol
576 case protType of
Jens Geyer3b686532021-07-01 23:04:08 +0200577 prot_Binary : ProtocolFactory := TBinaryProtocolImpl.TFactory.Create;
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200578 prot_JSON : ProtocolFactory := TJSONProtocolImpl.TFactory.Create;
Jens Geyerf0e63312015-03-01 18:47:49 +0100579 prot_Compact : ProtocolFactory := TCompactProtocolImpl.TFactory.Create;
Jake Farrell27274222011-11-10 20:32:44 +0000580 else
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200581 raise Exception.Create('Unhandled protocol');
Jake Farrell27274222011-11-10 20:32:44 +0000582 end;
Roger Meier3bef8c22012-10-06 06:58:00 +0000583 ASSERT( ProtocolFactory <> nil);
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200584 Console.WriteLine('- '+THRIFT_PROTOCOLS[protType]+' protocol');
Jake Farrell27274222011-11-10 20:32:44 +0000585
Jens Geyer20a86d62021-04-02 11:34:08 +0200586 config := nil; // TODO
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200587 case endpoint of
Jake Farrell27274222011-11-10 20:32:44 +0000588
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200589 trns_Sockets : begin
590 Console.WriteLine('- sockets (port '+IntToStr(port)+')');
591 if (trns_Buffered in layered) then Console.WriteLine('- buffered');
Jens Geyer41f47af2019-11-09 23:24:52 +0100592 servertrans := TServerSocketImpl.Create( Port, DEFAULT_THRIFT_TIMEOUT, (trns_Buffered in layered));
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200593 end;
594
Jens Geyer02230912019-04-03 01:12:51 +0200595 trns_MsxmlHttp,
596 trns_WinHttp : begin
597 raise Exception.Create('HTTP server transport not implemented');
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200598 end;
599
600 trns_NamedPipes : begin
601 Console.WriteLine('- named pipe ('+sPipeName+')');
Jens Geyer20a86d62021-04-02 11:34:08 +0200602 namedpipe := TNamedPipeServerTransportImpl.Create( sPipeName, PIPEFLAGS, config);
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200603 servertrans := namedpipe;
604 end;
605
606 trns_AnonPipes : begin
607 Console.WriteLine('- anonymous pipes');
608 anonymouspipe := TAnonymousPipeServerTransportImpl.Create;
609 servertrans := anonymouspipe;
610 end
611
612 else
613 raise Exception.Create('Unhandled endpoint transport');
Roger Meier3bef8c22012-10-06 06:58:00 +0000614 end;
615 ASSERT( servertrans <> nil);
616
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200617 if UseSSL then begin
618 raise Exception.Create('SSL not implemented');
619 end;
620
621 if (trns_Framed in layered) then begin
Roger Meier3bef8c22012-10-06 06:58:00 +0000622 Console.WriteLine('- framed transport');
Jens Geyera019cda2019-11-09 23:24:52 +0100623 TransportFactory := TFramedTransportImpl.TFactory.Create;
Roger Meier3bef8c22012-10-06 06:58:00 +0000624 end
625 else begin
626 TransportFactory := TTransportFactoryImpl.Create;
627 end;
628 ASSERT( TransportFactory <> nil);
629
630 testHandler := TTestHandlerImpl.Create;
Jake Farrell27274222011-11-10 20:32:44 +0000631 testProcessor := TThriftTest.TProcessorImpl.Create( testHandler );
Jake Farrell27274222011-11-10 20:32:44 +0000632
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200633 case servertype of
634 srv_Simple : begin
635 ServerEngine := TSimpleServer.Create( testProcessor, ServerTrans, TransportFactory, ProtocolFactory);
636 end;
637
638 srv_Nonblocking : begin
639 raise Exception.Create(SERVER_TYPES[servertype]+' server not implemented');
640 end;
641
642 srv_Threadpool,
643 srv_Threaded: begin
644 if numWorker > 1 then {use here};
645 raise Exception.Create(SERVER_TYPES[servertype]+' server not implemented');
646 end;
647
648 else
649 raise Exception.Create('Unhandled server type');
650 end;
651 ASSERT( ServerEngine <> nil);
Jake Farrell27274222011-11-10 20:32:44 +0000652
653 testHandler.SetServer( ServerEngine);
654
Jens Geyer01640402013-09-25 21:12:21 +0200655 // test events?
656 if ServerEvents then begin
657 Console.WriteLine('- server events test enabled');
658 ServerEngine.ServerEvents := TServerEventsImpl.Create;
659 end;
660
Roger Meier3bef8c22012-10-06 06:58:00 +0000661 // start the client now when we have the anon handles, but before the server starts
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200662 if endpoint = trns_AnonPipes
Roger Meier79655fb2012-10-20 20:59:41 +0000663 then LaunchAnonPipeChild( ExtractFilePath(ParamStr(0))+'client.exe', anonymouspipe);
Jake Farrell27274222011-11-10 20:32:44 +0000664
Jens Geyer06045cf2013-03-27 20:26:25 +0200665 // install Ctrl+C handler before the server starts
666 g_Handler := testHandler;
667 SetConsoleCtrlHandler( @MyConsoleEventHandler, TRUE);
Roger Meier3bef8c22012-10-06 06:58:00 +0000668
669 Console.WriteLine('');
Jens Geyer06045cf2013-03-27 20:26:25 +0200670 repeat
671 Console.WriteLine('Starting the server ...');
672 serverEngine.Serve;
673 until {$IFDEF RunEndless} FALSE {$ELSE} TRUE {$ENDIF};
674
Jake Farrell27274222011-11-10 20:32:44 +0000675 testHandler.SetServer( nil);
Jens Geyer06045cf2013-03-27 20:26:25 +0200676 g_Handler := nil;
Jake Farrell27274222011-11-10 20:32:44 +0000677
678 except
Jens Geyerf8a1b7a2014-09-24 00:26:46 +0200679 on E: EAbort do raise;
680 on E: Exception do begin
681 Console.WriteLine( E.Message + #10 + E.StackTrace );
Jake Farrell27274222011-11-10 20:32:44 +0000682 end;
683 end;
684 Console.WriteLine( 'done.');
685end;
686
Jens Geyer06045cf2013-03-27 20:26:25 +0200687
Jake Farrell27274222011-11-10 20:32:44 +0000688end.