THRIFT-2718 Align cmdline help and return codes for Thrift test server/client
Client: Delphi
Patch: Jens Geyer
diff --git a/lib/delphi/test/TestServer.pas b/lib/delphi/test/TestServer.pas
index 9d06e8e..286047d 100644
--- a/lib/delphi/test/TestServer.pas
+++ b/lib/delphi/test/TestServer.pas
@@ -81,6 +81,9 @@
         procedure SetServer( const AServer : IServer );
       end;
 
+      class procedure PrintCmdLineHelp;
+      class procedure InvalidArgs;
+
       class procedure LaunchAnonPipeChild( const app : string; const transport : IAnonymousPipeServerTransport);
       class procedure Execute( const args: array of string);
   end;
@@ -437,6 +440,34 @@
 { TTestServer }
 
 
+class procedure TTestServer.PrintCmdLineHelp;
+const HELPTEXT = ' [options]'#10
+               + #10
+               + 'Allowed options:'#10
+               + '  -h [ --help ]               produce help message'#10
+               + '  --port arg (=9090)          Port number to listen'#10
+               + '  --domain-socket arg         Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)'#10
+               + '  --named-pipe arg            Windows Named Pipe (e.g. MyThriftPipe)'#10
+               + '  --server-type arg (=simple) type of server, "simple", "thread-pool",'#10
+               + '                              "threaded", or "nonblocking"'#10
+               + '  --transport arg (=socket)   transport: buffered, framed, http, anonpipe'#10
+               + '  --protocol arg (=binary)    protocol: binary, compact, json'#10
+               + '  --ssl                       Encrypted Transport using SSL'#10
+               + '  --processor-events          processor-events'#10
+               + '  -n [ --workers ] arg (=4)   Number of thread pools workers. Only valid for'#10
+               + '                              thread-pool server type'#10
+               ;
+begin
+  Console.WriteLine( ChangeFileExt(ExtractFileName(ParamStr(0)),'') + HELPTEXT);
+end;
+
+class procedure TTestServer.InvalidArgs;
+begin
+  Console.WriteLine( 'Invalid args.');
+  Console.WriteLine( ChangeFileExt(ExtractFileName(ParamStr(0)),'') + ' -h for more information');
+  Abort;
+end;
+
 class procedure TTestServer.LaunchAnonPipeChild( const app : string; const transport : IAnonymousPipeServerTransport);
 //Launch child process and pass R/W anonymous pipe handles on cmd line.
 //This is a simple example and does not include elevation or other
@@ -480,10 +511,8 @@
 
 class procedure TTestServer.Execute( const args: array of string);
 var
-  UseBufferedSockets : Boolean;
-  UseFramed : Boolean;
   Port : Integer;
-  AnonPipe, ServerEvents : Boolean;
+  ServerEvents : Boolean;
   sPipeName : string;
   testHandler : ITestHandler;
   testProcessor : IProcessor;
@@ -493,9 +522,13 @@
   namedpipe : INamedPipeServerTransport;
   TransportFactory : ITransportFactory;
   ProtocolFactory : IProtocolFactory;
-  i : Integer;
+  i, numWorker : Integer;
   s : string;
-  protType, p : TKnownProtocol;
+  protType : TKnownProtocol;
+  servertype : TServerType;
+  endpoint : TEndpointTransport;
+  layered : TLayeredTransports;
+  UseSSL : Boolean; // include where appropriate (TLayeredTransport?)
 const
   // pipe timeouts to be used
   DEBUG_TIMEOUT   = 30 * 1000;
@@ -503,63 +536,96 @@
   TIMEOUT         = RELEASE_TIMEOUT;
 begin
   try
-    UseBufferedSockets := False;
-    UseFramed := False;
-    AnonPipe := FALSE;
     ServerEvents := FALSE;
     protType := prot_Binary;
+    servertype := srv_Simple;
+    endpoint := trns_Sockets;
+    layered := [];
+    UseSSL := FALSE;
     Port := 9090;
     sPipeName := '';
+    numWorker := 4;
 
     i := 0;
     while ( i < Length(args) ) do begin
       s := args[i];
       Inc(i);
 
-      if StrToIntDef( s, -1) > 0 then
-      begin
-        Port :=  StrToIntDef( s, Port);
+      // Allowed options:
+      if (s = '-h') or (s = '--help') then begin
+        // -h [ --help ]               produce help message
+        PrintCmdLineHelp;
+        Exit;
       end
-      else if ( s = 'raw' ) then
-      begin
-        // as default
+      else if (s = '--port') then begin
+        // --port arg (=9090)          Port number to listen
+        s := args[i];
+        Inc(i);
+        Port := StrToIntDef( s, Port);
       end
-      else if ( s = 'buffered' ) then
-      begin
-        UseBufferedSockets := True;
+      else if (s = '--domain-socket') then begin
+        // --domain-socket arg         Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)
+        raise Exception.Create('domain-socket not supported');
       end
-      else if ( s = 'framed' ) then
-      begin
-        UseFramed := True;
-      end
-      else if (s = '-pipe') then
-      begin
+      else if (s = '--named-pipe') then begin
+        // --named-pipe arg            Windows Named Pipe (e.g. MyThriftPipe)
+        endpoint := trns_NamedPipes;
         sPipeName := args[i];  // -pipe <name>
         Inc( i );
       end
-      else if (s = '-anon') then
-      begin
-        AnonPipe := TRUE;
-      end
-      else if (s = '-prot') then  // -prot JSON|binary
-      begin
+      else if (s = '--server-type') then begin
+        // --server-type arg (=simple) type of server,
+        // arg = "simple", "thread-pool", "threaded", or "nonblocking"
         s := args[i];
-        Inc( i );
-        for p:= Low(TKnownProtocol) to High(TKnownProtocol) do begin
-          if SameText( s, KNOWN_PROTOCOLS[p]) then begin
-            protType := p;
-            Break;
-          end;
-        end;
+        Inc(i);
+
+        if      s = 'simple'      then servertype := srv_Simple
+        else if s = 'thread-pool' then servertype := srv_Threadpool
+        else if s = 'threaded'    then servertype := srv_Threaded
+        else if s = 'nonblocking' then servertype := srv_Nonblocking
+        else InvalidArgs;
       end
-      else if ( s = '-events' ) then
-      begin
-        ServerEvents := True;
+      else if (s = '--transport') then begin
+        // --transport arg (=buffered) transport: buffered, framed, http
+        s := args[i];
+        Inc(i);
+
+        if      s = 'buffered' then Include( layered, trns_Buffered)
+        else if s = 'framed'   then Include( layered, trns_Framed)
+        else if s = 'http'     then endpoint := trns_Http
+        else if s = 'anonpipe' then endpoint := trns_AnonPipes
+        else InvalidArgs;
+      end
+      else if (s = '--protocol') then begin
+        // --protocol arg (=binary)    protocol: binary, compact, json
+        s := args[i];
+        Inc(i);
+
+        if      s = 'binary'   then protType := prot_Binary
+        else if s = 'compact'  then protType := prot_Compact
+        else if s = 'json'     then protType := prot_JSON
+        else InvalidArgs;
+      end
+      else if (s = '--ssl') then begin
+        // --ssl     Encrypted Transport using SSL
+        UseSSL := TRUE;
+      end
+      else if (s = '--processor-events') then begin
+         // --processor-events          processor-events
+        ServerEvents := TRUE;
+      end
+      else if (s = '-n') or (s = '--workers') then begin
+        // -n [ --workers ] arg (=4)   Number of thread pools workers.
+        // Only valid for thread-pool server type
+        s := args[i];
+        numWorker := StrToIntDef(s,0);
+        if numWorker > 0
+        then Inc(i)
+        else numWorker := 4;
       end
       else begin
-        // Fall back to the older boolean syntax
-        UseBufferedSockets := StrToBoolDef( args[1], UseBufferedSockets);
-      end
+        InvalidArgs;
+      end;
     end;
 
 
@@ -567,34 +633,49 @@
 
     // create protocol factory, default to BinaryProtocol
     case protType of
-      prot_Binary:  ProtocolFactory := TBinaryProtocolImpl.TFactory.Create( BINARY_STRICT_READ, BINARY_STRICT_WRITE);
-      prot_JSON  :  ProtocolFactory := TJSONProtocolImpl.TFactory.Create;
+      prot_Binary  :  ProtocolFactory := TBinaryProtocolImpl.TFactory.Create( BINARY_STRICT_READ, BINARY_STRICT_WRITE);
+      prot_JSON    :  ProtocolFactory := TJSONProtocolImpl.TFactory.Create;
+      prot_Compact :  raise Exception.Create('Compact protocol not implemented');
     else
-      ASSERT( FALSE);  // unhandled case!
-      ProtocolFactory := TBinaryProtocolImpl.TFactory.Create( BINARY_STRICT_READ, BINARY_STRICT_WRITE);
+      raise Exception.Create('Unhandled protocol');
     end;
     ASSERT( ProtocolFactory <> nil);
-    Console.WriteLine('- '+KNOWN_PROTOCOLS[protType]+' protocol');
+    Console.WriteLine('- '+THRIFT_PROTOCOLS[protType]+' protocol');
 
+    case endpoint of
 
-    if sPipeName <> '' then begin
-      Console.WriteLine('- named pipe ('+sPipeName+')');
-      namedpipe   := TNamedPipeServerTransportImpl.Create( sPipeName, 4096, PIPE_UNLIMITED_INSTANCES, TIMEOUT);
-      servertrans := namedpipe;
-    end
-    else if AnonPipe then begin
-      Console.WriteLine('- anonymous pipes');
-      anonymouspipe := TAnonymousPipeServerTransportImpl.Create;
-      servertrans   := anonymouspipe;
-    end
-    else begin
-      Console.WriteLine('- sockets (port '+IntToStr(port)+')');
-      if UseBufferedSockets then Console.WriteLine('- buffered sockets');
-      servertrans := TServerSocketImpl.Create( Port, 0, UseBufferedSockets);
+      trns_Sockets : begin
+        Console.WriteLine('- sockets (port '+IntToStr(port)+')');
+        if (trns_Buffered in layered) then Console.WriteLine('- buffered');
+        servertrans := TServerSocketImpl.Create( Port, 0, (trns_Buffered in layered));
+      end;
+
+      trns_Http : begin
+        raise Exception.Create('HTTP server transport not implemented');
+      end;
+
+      trns_NamedPipes : begin
+        Console.WriteLine('- named pipe ('+sPipeName+')');
+        namedpipe   := TNamedPipeServerTransportImpl.Create( sPipeName, 4096, PIPE_UNLIMITED_INSTANCES, TIMEOUT);
+        servertrans := namedpipe;
+      end;
+
+      trns_AnonPipes : begin
+        Console.WriteLine('- anonymous pipes');
+        anonymouspipe := TAnonymousPipeServerTransportImpl.Create;
+        servertrans   := anonymouspipe;
+      end
+
+    else
+      raise Exception.Create('Unhandled endpoint transport');
     end;
     ASSERT( servertrans <> nil);
 
-    if UseFramed then begin
+    if UseSSL then begin
+      raise Exception.Create('SSL not implemented');
+    end;
+
+    if (trns_Framed in layered) then begin
       Console.WriteLine('- framed transport');
       TransportFactory := TFramedTransportImpl.TFactory.Create
     end
@@ -606,10 +687,25 @@
     testHandler   := TTestHandlerImpl.Create;
     testProcessor := TThriftTest.TProcessorImpl.Create( testHandler );
 
-    ServerEngine := TSimpleServer.Create( testProcessor,
-                                          ServerTrans,
-                                          TransportFactory,
-                                          ProtocolFactory);
+    case servertype of
+      srv_Simple      : begin
+        ServerEngine := TSimpleServer.Create( testProcessor, ServerTrans, TransportFactory, ProtocolFactory);
+      end;
+
+      srv_Nonblocking : begin
+        raise Exception.Create(SERVER_TYPES[servertype]+' server not implemented');
+      end;
+
+      srv_Threadpool,
+      srv_Threaded: begin
+        if numWorker > 1 then {use here};
+        raise Exception.Create(SERVER_TYPES[servertype]+' server not implemented');
+      end;
+
+    else
+      raise Exception.Create('Unhandled server type');
+    end;
+    ASSERT( ServerEngine <> nil);
 
     testHandler.SetServer( ServerEngine);
 
@@ -620,7 +716,7 @@
     end;
 
     // start the client now when we have the anon handles, but before the server starts
-    if AnonPipe
+    if endpoint = trns_AnonPipes
     then LaunchAnonPipeChild( ExtractFilePath(ParamStr(0))+'client.exe', anonymouspipe);
 
     // install Ctrl+C handler before the server starts
@@ -637,9 +733,9 @@
     g_Handler := nil;
 
   except
-    on E: Exception do
-    begin
-      Console.Write( E.Message);
+    on E: EAbort do raise;
+    on E: Exception do begin
+      Console.WriteLine( E.Message + #10 + E.StackTrace );
     end;
   end;
   Console.WriteLine( 'done.');