source upload
This commit is contained in:
863
contrib/fundamentals/TCP/Tests/flcTCPTest_ClientServer.pas
Normal file
863
contrib/fundamentals/TCP/Tests/flcTCPTest_ClientServer.pas
Normal file
@@ -0,0 +1,863 @@
|
||||
{ 2020/05/11 5.01 Move tests from unit flcTests into seperate units. }
|
||||
|
||||
{$INCLUDE flcTCPTest.inc}
|
||||
|
||||
unit flcTCPTest_ClientServer;
|
||||
|
||||
interface
|
||||
|
||||
{$IFDEF TCPCLIENTSERVER_TEST}
|
||||
uses
|
||||
{$IFDEF OS_MSWIN}
|
||||
Windows,
|
||||
{$ENDIF}
|
||||
SysUtils,
|
||||
SyncObjs,
|
||||
Classes,
|
||||
|
||||
flcStdTypes,
|
||||
flcTCPConnection,
|
||||
flcTCPClient,
|
||||
flcTCPServer;
|
||||
{$ENDIF}
|
||||
|
||||
|
||||
|
||||
{$IFDEF TCPCLIENTSERVER_TEST}
|
||||
{ }
|
||||
{ TCP ClientServer Test Object }
|
||||
{ }
|
||||
type
|
||||
TTCPClientServerTestObj = class
|
||||
Lock : TCriticalSection;
|
||||
constructor Create;
|
||||
destructor Destroy; override;
|
||||
procedure Log(Msg: String);
|
||||
procedure ClientLog(Client: TF5TCPClient; LogType: TTCPClientLogType; Msg: String; LogLevel: Integer);
|
||||
procedure ServerLog(Sender: TF5TCPServer; LogType: TTCPLogType; Msg: String; LogLevel: Integer);
|
||||
end;
|
||||
|
||||
TTCPClientServerBlockTestObj = class
|
||||
FinC, FinS : Boolean;
|
||||
procedure ClientExec(Client: TF5TCPClient; Connection: TTCPBlockingConnection; var CloseOnExit: Boolean);
|
||||
procedure ServerExec(Sender: TTCPServerClient; Connection: TTCPBlockingConnection; var CloseOnExit: Boolean);
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Test functions }
|
||||
{ }
|
||||
type
|
||||
TF5TCPClientArray = array of TF5TCPClient;
|
||||
TTCPServerClientArray = array of TTCPServerClient;
|
||||
|
||||
procedure TestClientServer_ReadWrite_Blocks(
|
||||
const TestClientCount: Integer;
|
||||
const TestLargeBlock: Boolean;
|
||||
const DebugObj : TTCPClientServerTestObj;
|
||||
const C: TF5TCPClientArray;
|
||||
const T: TTCPServerClientArray);
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Test }
|
||||
{ }
|
||||
procedure Test;
|
||||
{$ENDIF}
|
||||
|
||||
|
||||
|
||||
implementation
|
||||
|
||||
{$IFDEF TCPCLIENTSERVER_TEST}
|
||||
uses
|
||||
flcSocketLib,
|
||||
flcTimers;
|
||||
{$ENDIF}
|
||||
|
||||
|
||||
|
||||
{$IFDEF TCPCLIENTSERVER_TEST}
|
||||
{$ASSERTIONS ON}
|
||||
{ }
|
||||
{ TCP ClientServer Test Object }
|
||||
{ }
|
||||
|
||||
{ TTCPClientServerTestObj }
|
||||
|
||||
constructor TTCPClientServerTestObj.Create;
|
||||
begin
|
||||
inherited Create;
|
||||
Lock := TCriticalSection.Create;
|
||||
end;
|
||||
|
||||
destructor TTCPClientServerTestObj.Destroy;
|
||||
begin
|
||||
FreeAndNil(Lock);
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
{$IFDEF TCP_TEST_LOG_TO_CONSOLE}
|
||||
procedure TTCPClientServerTestObj.Log(Msg: String);
|
||||
var S : String;
|
||||
begin
|
||||
S := FormatDateTime('hh:nn:ss.zzz', Now) + ' ' + Msg;
|
||||
Lock.Acquire;
|
||||
try
|
||||
Writeln(S);
|
||||
finally
|
||||
Lock.Release;
|
||||
end;
|
||||
end;
|
||||
{$ELSE}
|
||||
procedure TTCPClientServerTestObj.Log(Msg: String);
|
||||
begin
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
procedure TTCPClientServerTestObj.ClientLog(Client: TF5TCPClient; LogType: TTCPClientLogType; Msg: String; LogLevel: Integer);
|
||||
begin
|
||||
Log('C[' + IntToStr(Client.Tag) + ']:' + Msg);
|
||||
end;
|
||||
|
||||
procedure TTCPClientServerTestObj.ServerLog(Sender: TF5TCPServer; LogType: TTCPLogType; Msg: String; LogLevel: Integer);
|
||||
begin
|
||||
Log('S:' + Msg);
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ TTCPClientServerBlockTestObj }
|
||||
|
||||
procedure TTCPClientServerBlockTestObj.ClientExec(Client: TF5TCPClient;Connection: TTCPBlockingConnection; var CloseOnExit: Boolean);
|
||||
var
|
||||
B1 : LongWord;
|
||||
begin
|
||||
Sleep(200);
|
||||
|
||||
B1 := 1234;
|
||||
Connection.Write(B1, 4, 10000);
|
||||
|
||||
B1 := 0;
|
||||
Connection.Read(B1, 4, 10000);
|
||||
Assert(B1 = 22222);
|
||||
|
||||
FinC := True;
|
||||
end;
|
||||
|
||||
procedure TTCPClientServerBlockTestObj.ServerExec(Sender: TTCPServerClient; Connection: TTCPBlockingConnection; var CloseOnExit: Boolean);
|
||||
var
|
||||
B1 : LongWord;
|
||||
begin
|
||||
B1 := 0;
|
||||
Connection.Read(B1, 4, 10000);
|
||||
Assert(B1 = 1234);
|
||||
|
||||
B1 := 22222;
|
||||
Connection.Write(B1, 4, 10000);
|
||||
|
||||
FinS := True;
|
||||
end;
|
||||
|
||||
|
||||
|
||||
{ }
|
||||
{ Test }
|
||||
{ }
|
||||
procedure TestClientServer_ReadWrite_Blocks(
|
||||
const TestClientCount: Integer;
|
||||
const TestLargeBlock: Boolean;
|
||||
const DebugObj : TTCPClientServerTestObj;
|
||||
const C: TF5TCPClientArray;
|
||||
const T: TTCPServerClientArray);
|
||||
const
|
||||
LargeBlockSize = 256 * 1024;
|
||||
var
|
||||
K, I, J : Integer;
|
||||
F : RawByteString;
|
||||
B : Byte;
|
||||
begin
|
||||
// read & write (small block): client to server
|
||||
for K := 0 to TestClientCount - 1 do
|
||||
C[K].Connection.WriteByteString('Fundamentals');
|
||||
for K := 0 to TestClientCount - 1 do
|
||||
begin
|
||||
DebugObj.Log('{RWS:' + IntToStr(K + 1) + ':A}');
|
||||
I := 0;
|
||||
repeat
|
||||
Inc(I);
|
||||
Sleep(1);
|
||||
until (T[K].Connection.ReadBufferUsed >= 12) or (I >= 5000);
|
||||
DebugObj.Log('{RWS:' + IntToStr(K + 1) + ':B}');
|
||||
Assert(T[K].Connection.ReadBufferUsed = 12);
|
||||
F := T[K].Connection.PeekByteString(3);
|
||||
Assert(F = 'Fun');
|
||||
Assert(T[K].Connection.PeekByte(B));
|
||||
Assert(B = Ord('F'));
|
||||
F := T[K].Connection.ReadByteString(12);
|
||||
Assert(F = 'Fundamentals');
|
||||
DebugObj.Log('{RWS:' + IntToStr(K + 1) + ':Z}');
|
||||
end;
|
||||
// read & write (small block): server to client
|
||||
for K := 0 to TestClientCount - 1 do
|
||||
T[K].Connection.WriteByteString('123');
|
||||
for K := 0 to TestClientCount - 1 do
|
||||
begin
|
||||
C[K].BlockingConnection.WaitForReceiveData(3, 5000);
|
||||
F := C[K].Connection.ReadByteString(3);
|
||||
Assert(F = '123');
|
||||
end;
|
||||
if TestLargeBlock then
|
||||
begin
|
||||
// read & write (large block): client to server
|
||||
F := '';
|
||||
for I := 1 to LargeBlockSize do
|
||||
F := F + #1;
|
||||
for K := 0 to TestClientCount - 1 do
|
||||
C[K].Connection.WriteByteString(F);
|
||||
for K := 0 to TestClientCount - 1 do
|
||||
begin
|
||||
J := LargeBlockSize;
|
||||
repeat
|
||||
I := 0;
|
||||
repeat
|
||||
Inc(I);
|
||||
Sleep(1);
|
||||
Assert(C[K].State = csReady);
|
||||
Assert(T[K].State = scsReady);
|
||||
until (T[K].Connection.ReadBufferUsed > 0) or (I >= 5000);
|
||||
Assert(T[K].Connection.ReadBufferUsed > 0);
|
||||
F := T[K].Connection.ReadByteString(T[K].Connection.ReadBufferUsed);
|
||||
Assert(Length(F) > 0);
|
||||
for I := 1 to Length(F) do
|
||||
Assert(F[I] = #1);
|
||||
Dec(J, Length(F));
|
||||
until J <= 0;
|
||||
Assert(J = 0);
|
||||
Sleep(2);
|
||||
Assert(T[K].Connection.ReadBufferUsed = 0);
|
||||
end;
|
||||
// read & write (large block): server to client
|
||||
F := '';
|
||||
for I := 1 to LargeBlockSize do
|
||||
F := F + #1;
|
||||
for K := 0 to TestClientCount - 1 do
|
||||
T[K].Connection.WriteByteString(F);
|
||||
for K := 0 to TestClientCount - 1 do
|
||||
begin
|
||||
J := LargeBlockSize;
|
||||
repeat
|
||||
C[K].BlockingConnection.WaitForReceiveData(1, 5000);
|
||||
Assert(C[K].State = csReady);
|
||||
Assert(T[K].State = scsReady);
|
||||
Assert(C[K].Connection.ReadBufferUsed > 0);
|
||||
F := C[K].Connection.ReadByteString(C[K].Connection.ReadBufferUsed);
|
||||
Assert(Length(F) > 0);
|
||||
for I := 1 to Length(F) do
|
||||
Assert(F[I] = #1);
|
||||
Dec(J, Length(F));
|
||||
until J <= 0;
|
||||
Assert(J = 0);
|
||||
Sleep(2);
|
||||
Assert(C[K].Connection.ReadBufferUsed = 0);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TestClientServer_ReadWrite(
|
||||
const TestClientCount: Integer;
|
||||
const TestLargeBlock: Boolean
|
||||
);
|
||||
|
||||
procedure WaitClientConnected(const Client: TF5TCPClient);
|
||||
var I : Integer;
|
||||
begin
|
||||
I := 0;
|
||||
repeat
|
||||
Inc(I);
|
||||
Sleep(1);
|
||||
until (I >= 8000) or
|
||||
(Client.State in [csReady, csClosed]);
|
||||
Assert(Client.State = csReady);
|
||||
Assert(Client.Connection.State = cnsConnected);
|
||||
end;
|
||||
|
||||
var C : TF5TCPClientArray;
|
||||
S : TF5TCPServer;
|
||||
T : TTCPServerClientArray;
|
||||
TSC : TTCPServerClient;
|
||||
I, K : Integer;
|
||||
DebugObj : TTCPClientServerTestObj;
|
||||
begin
|
||||
DebugObj := TTCPClientServerTestObj.Create;
|
||||
S := TF5TCPServer.Create(nil);
|
||||
SetLength(C, TestClientCount);
|
||||
SetLength(T, TestClientCount);
|
||||
for K := 0 to TestClientCount - 1 do
|
||||
begin
|
||||
C[K] := TF5TCPClient.Create(nil);
|
||||
// init client
|
||||
C[K].Tag := K + 1;
|
||||
C[K].OnLog := DebugObj.ClientLog;
|
||||
end;
|
||||
try
|
||||
// init server
|
||||
S.OnLog := DebugObj.ServerLog;
|
||||
S.AddressFamily := iaIP4;
|
||||
S.BindAddress := '127.0.0.1';
|
||||
S.ServerPort := 12545;
|
||||
S.MaxClients := -1;
|
||||
Assert(S.State = ssInit);
|
||||
Assert(not S.Active);
|
||||
// start server
|
||||
S.Start;
|
||||
Assert(S.Active);
|
||||
I := 0;
|
||||
repeat
|
||||
Inc(I);
|
||||
Sleep(1);
|
||||
until (S.State <> ssStarting) or (I >= 5000);
|
||||
Sleep(100);
|
||||
Assert(S.State = ssReady);
|
||||
Assert(S.ClientCount = 0);
|
||||
for K := 0 to TestClientCount - 1 do
|
||||
begin
|
||||
// init client
|
||||
C[K].AddressFamily := cafIP4;
|
||||
C[K].Host := '127.0.0.1';
|
||||
C[K].Port := '12545';
|
||||
Assert(C[K].State = csInit);
|
||||
Assert(not C[K].Active);
|
||||
// start client
|
||||
C[K].WaitForStartup := True;
|
||||
C[K].Start;
|
||||
Assert(Assigned(C[K].Connection));
|
||||
Assert(C[K].Active);
|
||||
end;
|
||||
for K := 0 to TestClientCount - 1 do
|
||||
// wait for client to connect
|
||||
WaitClientConnected(C[K]);
|
||||
// wait for server connections
|
||||
I := 0;
|
||||
repeat
|
||||
Inc(I);
|
||||
Sleep(1);
|
||||
until (S.ClientCount >= TestClientCount) or (I >= 5000);
|
||||
Assert(S.ClientCount = TestClientCount);
|
||||
// wait for server clients
|
||||
TSC := S.ClientIterateFirst;
|
||||
for K := 0 to TestClientCount - 1 do
|
||||
begin
|
||||
T[K] := TSC;
|
||||
Assert(Assigned(T[K]));
|
||||
Assert(T[K].State in [scsStarting, scsNegotiating, scsReady]);
|
||||
Assert(T[K].Connection.State in [cnsProxyNegotiation, cnsConnected]);
|
||||
TSC.ReleaseReference;
|
||||
TSC := S.ClientIterateNext(TSC);
|
||||
end;
|
||||
// test read/write
|
||||
TestClientServer_ReadWrite_Blocks(
|
||||
TestClientCount,
|
||||
TestLargeBlock,
|
||||
DebugObj,
|
||||
C, T);
|
||||
// release reference
|
||||
for K := 0 to TestClientCount - 1 do
|
||||
T[K].ReleaseReference;
|
||||
// stop clients
|
||||
for K := TestClientCount - 1 downto 0 do
|
||||
begin
|
||||
C[K].Stop;
|
||||
Assert(C[K].State = csStopped);
|
||||
end;
|
||||
I := 0;
|
||||
repeat
|
||||
Inc(I);
|
||||
Sleep(1);
|
||||
until (S.ClientCount = 0) or (I >= 5000);
|
||||
Assert(S.ClientCount = 0);
|
||||
// stop server
|
||||
S.Stop;
|
||||
Assert(not S.Active);
|
||||
finally
|
||||
for K := TestClientCount - 1 downto 0 do
|
||||
begin
|
||||
C[K].Finalise;
|
||||
FreeAndNil(C[K]);
|
||||
end;
|
||||
S.Finalise;
|
||||
FreeAndNil(S);
|
||||
DebugObj.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure Test_ClientServer_StopStart;
|
||||
const
|
||||
TestClientCount = 10;
|
||||
TestRepeatCount = 3;
|
||||
var C : array of TF5TCPClient;
|
||||
S : TF5TCPServer;
|
||||
I, K : Integer;
|
||||
J : Integer;
|
||||
DebugObj : TTCPClientServerTestObj;
|
||||
begin
|
||||
DebugObj := TTCPClientServerTestObj.Create;
|
||||
S := TF5TCPServer.Create(nil);
|
||||
SetLength(C, TestClientCount);
|
||||
for K := 0 to TestClientCount - 1 do
|
||||
begin
|
||||
C[K] := TF5TCPClient.Create(nil);
|
||||
// init client
|
||||
C[K].Tag := K + 1;
|
||||
C[K].OnLog := DebugObj.ClientLog;
|
||||
end;
|
||||
try
|
||||
// init server
|
||||
S.OnLog := DebugObj.ServerLog;
|
||||
S.AddressFamily := iaIP4;
|
||||
S.BindAddress := '127.0.0.1';
|
||||
S.ServerPort := 12645;
|
||||
S.MaxClients := -1;
|
||||
Assert(S.State = ssInit);
|
||||
Assert(not S.Active);
|
||||
// start server
|
||||
S.Start;
|
||||
Assert(S.Active);
|
||||
I := 0;
|
||||
repeat
|
||||
Inc(I);
|
||||
Sleep(1);
|
||||
until (S.State <> ssStarting) or (I >= 5000);
|
||||
Assert(S.State = ssReady);
|
||||
Assert(S.ClientCount = 0);
|
||||
// init clients
|
||||
for K := 0 to TestClientCount - 1 do
|
||||
begin
|
||||
C[K].AddressFamily := cafIP4;
|
||||
C[K].Host := '127.0.0.1';
|
||||
C[K].Port := '12645';
|
||||
C[K].WaitForStartup := True;
|
||||
Assert(C[K].State = csInit);
|
||||
Assert(not C[K].Active);
|
||||
end;
|
||||
// test quickly starting and stopping clients
|
||||
for J := 0 to TestRepeatCount - 1 do
|
||||
begin
|
||||
// start client
|
||||
for K := 0 to TestClientCount - 1 do
|
||||
begin
|
||||
C[K].Start;
|
||||
// connection must exist when Start exits
|
||||
Assert(Assigned(C[K].Connection));
|
||||
Assert(C[K].Active);
|
||||
end;
|
||||
// delay
|
||||
if J > 0 then
|
||||
Sleep(J - 1);
|
||||
// stop clients
|
||||
for K := TestClientCount - 1 downto 0 do
|
||||
begin
|
||||
C[K].Stop;
|
||||
Assert(C[K].State = csStopped);
|
||||
Assert(not Assigned(C[K].Connection));
|
||||
end;
|
||||
// delay
|
||||
if J > 0 then
|
||||
Sleep(J - 1);
|
||||
// re-start client
|
||||
for K := 0 to TestClientCount - 1 do
|
||||
begin
|
||||
C[K].Start;
|
||||
// connection must exist when Start exits
|
||||
Assert(Assigned(C[K].Connection));
|
||||
Assert(C[K].Active);
|
||||
end;
|
||||
// delay
|
||||
if J > 0 then
|
||||
Sleep(J - 1);
|
||||
// re-stop clients
|
||||
for K := TestClientCount - 1 downto 0 do
|
||||
begin
|
||||
C[K].Stop;
|
||||
Assert(C[K].State = csStopped);
|
||||
Assert(not Assigned(C[K].Connection));
|
||||
end;
|
||||
end;
|
||||
// stop server
|
||||
S.Stop;
|
||||
Assert(not S.Active);
|
||||
finally
|
||||
for K := TestClientCount - 1 downto 0 do
|
||||
begin
|
||||
C[K].Finalise;
|
||||
FreeAndNil(C[K]);
|
||||
end;
|
||||
S.Finalise;
|
||||
FreeAndNil(S);
|
||||
DebugObj.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure Test_ClientServer_ReadWrite;
|
||||
begin
|
||||
TestClientServer_ReadWrite(1, True);
|
||||
TestClientServer_ReadWrite(2, True);
|
||||
TestClientServer_ReadWrite(5, True);
|
||||
{$IFNDEF LINUX} // FAILS
|
||||
TestClientServer_ReadWrite(30, False);
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
procedure Test_ClientServer_Shutdown;
|
||||
var
|
||||
S : TF5TCPServer;
|
||||
C : TF5TCPClient;
|
||||
T : TTCPServerClient;
|
||||
B, X : RawByteString;
|
||||
I, L, N, M : Integer;
|
||||
begin
|
||||
S := TF5TCPServer.Create(nil);
|
||||
S.AddressFamily := iaIP4;
|
||||
S.BindAddress := '127.0.0.1';
|
||||
S.ServerPort := 12213;
|
||||
S.MaxClients := -1;
|
||||
S.Active := True;
|
||||
Sleep(100);
|
||||
|
||||
C := TF5TCPClient.Create(nil);
|
||||
C.LocalHost := '0.0.0.0';
|
||||
C.Host := '127.0.0.1';
|
||||
C.Port := '12213';
|
||||
C.WaitForStartup := True;
|
||||
C.UseWorkerThread := False;
|
||||
C.Active := True;
|
||||
Sleep(100);
|
||||
|
||||
Assert(C.State = csReady);
|
||||
|
||||
SetLength(B, 1024 * 1024);
|
||||
for I := 1 to Length(B) do
|
||||
B[I] := #1;
|
||||
L := C.Connection.WriteByteString(B);
|
||||
Assert(L > 1024);
|
||||
Sleep(1);
|
||||
|
||||
Assert(not C.IsShutdownComplete);
|
||||
C.Shutdown;
|
||||
for I := 1 to 10 do
|
||||
begin
|
||||
if C.IsShutdownComplete then
|
||||
break;
|
||||
Sleep(50);
|
||||
end;
|
||||
Assert(C.IsShutdownComplete);
|
||||
|
||||
T := S.ClientIterateFirst;
|
||||
Assert(Assigned(T));
|
||||
SetLength(X, L);
|
||||
M := 0;
|
||||
repeat
|
||||
N := T.Connection.Read(X[1], L);
|
||||
Inc(M, N);
|
||||
Sleep(10);
|
||||
until N <= 0;
|
||||
Assert(M = L);
|
||||
Sleep(100);
|
||||
|
||||
Assert(C.State = csClosed);
|
||||
Assert(T.State = scsClosed);
|
||||
|
||||
T.ReleaseReference;
|
||||
|
||||
C.Close;
|
||||
C.Finalise;
|
||||
C.Free;
|
||||
|
||||
S.Active := False;
|
||||
S.Finalise;
|
||||
S.Free;
|
||||
end;
|
||||
|
||||
procedure Test_ClientServer_Block;
|
||||
var
|
||||
S : TF5TCPServer;
|
||||
C : TF5TCPClient;
|
||||
DebugObj : TTCPClientServerTestObj;
|
||||
TestObj : TTCPClientServerBlockTestObj;
|
||||
begin
|
||||
DebugObj := TTCPClientServerTestObj.Create;
|
||||
TestObj := TTCPClientServerBlockTestObj.Create;
|
||||
|
||||
S := TF5TCPServer.Create(nil);
|
||||
S.OnLog := DebugObj.ServerLog;
|
||||
S.AddressFamily := iaIP4;
|
||||
S.BindAddress := '127.0.0.1';
|
||||
S.ServerPort := 12145;
|
||||
S.MaxClients := -1;
|
||||
S.UseWorkerThread := True;
|
||||
S.OnClientWorkerExecute := TestObj.ServerExec;
|
||||
S.Active := True;
|
||||
|
||||
Sleep(50);
|
||||
|
||||
C := TF5TCPClient.Create(nil);
|
||||
C.OnLog := DebugObj.ClientLog;
|
||||
C.LocalHost := '0.0.0.0';
|
||||
C.Host := '127.0.0.1';
|
||||
C.Port := '12145';
|
||||
C.WaitForStartup := True;
|
||||
C.UseWorkerThread := True;
|
||||
C.OnWorkerExecute := TestObj.ClientExec;
|
||||
C.Active := True;
|
||||
|
||||
repeat
|
||||
Sleep(1);
|
||||
until TestObj.FinC and TestObj.FinS;
|
||||
|
||||
C.Active := False;
|
||||
S.Active := False;
|
||||
|
||||
C.Finalise;
|
||||
FreeAndNil(C);
|
||||
S.Finalise;
|
||||
FreeAndNil(S);
|
||||
|
||||
TestObj.Free;
|
||||
DebugObj.Free;
|
||||
end;
|
||||
|
||||
procedure Test_ClientServer_RetryConnect;
|
||||
var
|
||||
S : TF5TCPServer;
|
||||
C : TF5TCPClient;
|
||||
DebugObj : TTCPClientServerTestObj;
|
||||
TestObj : TTCPClientServerBlockTestObj;
|
||||
I : Integer;
|
||||
begin
|
||||
DebugObj := TTCPClientServerTestObj.Create;
|
||||
TestObj := TTCPClientServerBlockTestObj.Create;
|
||||
|
||||
S := TF5TCPServer.Create(nil);
|
||||
S.OnLog := DebugObj.ServerLog;
|
||||
S.AddressFamily := iaIP4;
|
||||
S.BindAddress := '127.0.0.1';
|
||||
S.ServerPort := 12045;
|
||||
S.MaxClients := -1;
|
||||
S.UseWorkerThread := True;
|
||||
S.OnClientWorkerExecute := TestObj.ServerExec;
|
||||
|
||||
C := TF5TCPClient.Create(nil);
|
||||
C.OnLog := DebugObj.ClientLog;
|
||||
C.LocalHost := '0.0.0.0';
|
||||
C.Host := '127.0.0.1';
|
||||
C.Port := '12045';
|
||||
C.WaitForStartup := True;
|
||||
C.UseWorkerThread := True;
|
||||
C.OnWorkerExecute := TestObj.ClientExec;
|
||||
C.RetryFailedConnect := True;
|
||||
C.RetryFailedConnectDelaySec := 2;
|
||||
C.RetryFailedConnectMaxAttempts := 3;
|
||||
C.ReconnectOnDisconnect := False;
|
||||
C.Active := True;
|
||||
|
||||
Sleep(2000);
|
||||
|
||||
S.Active := True;
|
||||
|
||||
I := 0;
|
||||
repeat
|
||||
Sleep(1);
|
||||
Inc(I);
|
||||
until (TestObj.FinC and TestObj.FinS) or (I > 4000);
|
||||
Assert(TestObj.FinC and TestObj.FinS);
|
||||
|
||||
//S.Active := False;
|
||||
//Sleep(100000);
|
||||
|
||||
C.Active := False;
|
||||
S.Active := False;
|
||||
|
||||
C.Finalise;
|
||||
FreeAndNil(C);
|
||||
|
||||
S.Finalise;
|
||||
FreeAndNil(S);
|
||||
|
||||
TestObj.Free;
|
||||
DebugObj.Free;
|
||||
end;
|
||||
|
||||
procedure Test_ClientServer_Latency;
|
||||
|
||||
procedure DoYield;
|
||||
begin
|
||||
{$IFDEF DELPHI}
|
||||
{$IFDEF OS_MSWIN}
|
||||
Yield;
|
||||
{$ELSE}
|
||||
TThread.Yield;
|
||||
{$ENDIF}
|
||||
{$ELSE}
|
||||
TThread.Yield;
|
||||
{$ENDIF}
|
||||
end;
|
||||
|
||||
procedure WaitClientConnected(const Client: TF5TCPClient);
|
||||
var I : Integer;
|
||||
begin
|
||||
// wait for client to connect
|
||||
I := 0;
|
||||
repeat
|
||||
Inc(I);
|
||||
Sleep(1);
|
||||
until (I >= 8000) or
|
||||
(Client.State in [csReady, csClosed]);
|
||||
Assert(Client.State = csReady);
|
||||
Assert(Client.Connection.State = cnsConnected);
|
||||
end;
|
||||
|
||||
var C : TF5TCPClient;
|
||||
S : TF5TCPServer;
|
||||
TSC : TTCPServerClient;
|
||||
I, Nr : Integer;
|
||||
F : RawByteString;
|
||||
DebugObj : TTCPClientServerTestObj;
|
||||
T : Word64;
|
||||
Buf : array[0..15] of Byte;
|
||||
const
|
||||
Test1N = 5;
|
||||
begin
|
||||
DebugObj := TTCPClientServerTestObj.Create;
|
||||
DebugObj.Log('');
|
||||
DebugObj.Log('Test_ClientServer_Latency:');
|
||||
|
||||
S := TF5TCPServer.Create(nil);
|
||||
C := TF5TCPClient.Create(nil);
|
||||
// init client
|
||||
C.Tag := 1;
|
||||
C.OnLog := DebugObj.ClientLog;
|
||||
try
|
||||
// init server
|
||||
S.OnLog := DebugObj.ServerLog;
|
||||
S.AddressFamily := iaIP4;
|
||||
S.BindAddress := '127.0.0.1';
|
||||
Randomize;
|
||||
S.ServerPort := 12513 + Random(1000);
|
||||
S.MaxClients := -1;
|
||||
Assert(S.State = ssInit);
|
||||
Assert(not S.Active);
|
||||
// start server
|
||||
S.Start;
|
||||
Assert(S.Active);
|
||||
I := 0;
|
||||
repeat
|
||||
Inc(I);
|
||||
Sleep(10);
|
||||
until (S.State <> ssStarting) or (I >= 400);
|
||||
Sleep(100);
|
||||
Assert(S.State = ssReady);
|
||||
Assert(S.ClientCount = 0);
|
||||
// init client
|
||||
C.AddressFamily := cafIP4;
|
||||
C.Host := '127.0.0.1';
|
||||
C.Port := IntToStr(S.ServerPort);
|
||||
Assert(C.State = csInit);
|
||||
Assert(not C.Active);
|
||||
// start client
|
||||
C.WaitForStartup := True;
|
||||
C.Start;
|
||||
Assert(Assigned(C.Connection));
|
||||
Assert(C.Active);
|
||||
// wait for client to connect
|
||||
WaitClientConnected(C);
|
||||
// wait for server connections
|
||||
I := 0;
|
||||
repeat
|
||||
Inc(I);
|
||||
Sleep(10);
|
||||
until (S.ClientCount >= 1) or (I >= 10000);
|
||||
Assert(S.ClientCount = 1);
|
||||
// wait for server clients
|
||||
TSC := S.ClientIterateFirst;
|
||||
Assert(Assigned(TSC));
|
||||
Assert(TSC.State in [scsStarting, scsNegotiating, scsReady]);
|
||||
Assert(TSC.Connection.State in [cnsProxyNegotiation, cnsConnected]);
|
||||
for Nr := 1 to Test1N do
|
||||
begin
|
||||
// read & write (small block): client to server
|
||||
// read directly from connection before buffered
|
||||
T := GetMicroTick;
|
||||
C.Connection.WriteByteString('Fundamentals');
|
||||
repeat
|
||||
DoYield;
|
||||
F := TSC.Connection.ReadByteString(12);
|
||||
if F = 'Fundamentals' then
|
||||
break;
|
||||
until MicroTickDelta(T, GetMicroTick) >= 5000000; // 5s
|
||||
T := MicroTickDelta(T, GetMicroTick);
|
||||
DebugObj.Log(' Latency1_ClientToServer:' + IntToStr(T));
|
||||
Assert(F = 'Fundamentals');
|
||||
// read & write (small block): server to client
|
||||
// read directly from connection before buffered
|
||||
FillChar(Buf, SizeOf(Buf), 0);
|
||||
T := GetMicroTick;
|
||||
TSC.Connection.WriteByteString('123');
|
||||
repeat
|
||||
DoYield;
|
||||
if C.Connection.Read(Buf[0], 3) = 3 then
|
||||
if (Buf[0] = Ord('1')) and (Buf[1] = Ord('2')) and (Buf[2] = Ord('3')) then
|
||||
break;
|
||||
until MicroTickDelta(T, GetMicroTick) >= 5000000; // 5s
|
||||
T := MicroTickDelta(T, GetMicroTick);
|
||||
DebugObj.Log(' Latency2_ServerToClient:' + IntToStr(T));
|
||||
Assert((Buf[0] = Ord('1')) and (Buf[1] = Ord('2')) and (Buf[2] = Ord('3')));
|
||||
// read & write (small block): client to server
|
||||
T := GetMicroTick;
|
||||
C.Connection.WriteByteString('Fundamentals');
|
||||
repeat
|
||||
DoYield;
|
||||
until (TSC.Connection.ReadBufferUsed >= 12) or (MicroTickDelta(T, GetMicroTick) >= 5000000);
|
||||
T := MicroTickDelta(T, GetMicroTick);
|
||||
DebugObj.Log(' Latency3_ClientToServer:' + IntToStr(T));
|
||||
Assert(TSC.Connection.ReadBufferUsed = 12);
|
||||
F := TSC.Connection.ReadByteString(12);
|
||||
Assert(F = 'Fundamentals');
|
||||
// read & write (small block): server to client
|
||||
T := GetMicroTick;
|
||||
TSC.Connection.WriteByteString('123');
|
||||
repeat
|
||||
DoYield;
|
||||
until (C.Connection.ReadBufferUsed >= 3) or (MicroTickDelta(T, GetMicroTick) >= 5000000);
|
||||
T := MicroTickDelta(T, GetMicroTick);
|
||||
DebugObj.Log(' Latency4_ServerToClient:' + IntToStr(T));
|
||||
F := C.Connection.ReadByteString(3);
|
||||
Assert(F = '123');
|
||||
end;
|
||||
TSC.ReleaseReference;
|
||||
finally
|
||||
C.Free;
|
||||
S.Free;
|
||||
end;
|
||||
|
||||
FreeAndNil(DebugObj);
|
||||
end;
|
||||
|
||||
procedure Test;
|
||||
begin
|
||||
Test_ClientServer_ReadWrite;
|
||||
Test_ClientServer_StopStart;
|
||||
Test_ClientServer_Shutdown;
|
||||
Test_ClientServer_Block;
|
||||
Test_ClientServer_RetryConnect;
|
||||
Test_ClientServer_Block;
|
||||
Test_ClientServer_ReadWrite;
|
||||
Test_ClientServer_Latency;
|
||||
end;
|
||||
{$ENDIF}
|
||||
|
||||
|
||||
|
||||
end.
|
||||
|
Reference in New Issue
Block a user