Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Comment: | {1860} added regression tests to validate [80934ad438] fix |
---|---|
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
9c1e76510bc822c3173c7b627c8e105b |
User & Date: | ab 2015-09-08 15:35:53 |
2015-09-09
| ||
07:19 | {1861} defined ConfigurationRestMethod at TSQLRestServerURIContext level - since may be used outside TDDDSocketThreadSettings scope check-in: 0692929d10 user: ab tags: trunk | |
2015-09-08
| ||
15:35 | {1860} added regression tests to validate [80934ad438] fix check-in: 9c1e76510b user: ab tags: trunk | |
15:33 | {1859} fixed potential race condition when several BatchSend() with transactions are processed on the server side - thanks oz for the feedback! check-in: 80934ad438 user: ab tags: trunk | |
Changes to SQLite3/mORMotSelfTests.pas.
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
AddCase(TTestBasicClasses); // *) AddCase(TTestClientServerAccess); // (* AddCase(TTestServiceOrientedArchitecture); AddCase(TTestBidirectionalRemoteConnection); AddCase(TTestExternalDatabase); AddCase(TTestMultiThreadProcess); AddCase(TTestDDDSharedUnits); //exit; // *) end; {$endif DELPHI5OROLDER} procedure SQLite3ConsoleTests; begin {$ifdef MSWINDOWS} |
| |
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
AddCase(TTestBasicClasses); // *) AddCase(TTestClientServerAccess); // (* AddCase(TTestServiceOrientedArchitecture); AddCase(TTestBidirectionalRemoteConnection); AddCase(TTestExternalDatabase); AddCase(TTestMultiThreadProcess); AddCase([TTestDDDSharedUnits,TTestDDDMultiThread]); //exit; // *) end; {$endif DELPHI5OROLDER} procedure SQLite3ConsoleTests; begin {$ifdef MSWINDOWS} |
Changes to SynSelfTests.pas.
868
869
870
871
872
873
874
875
876
877
878
879
880
881
.....
13799
13800
13801
13802
13803
13804
13805
13806
13807
13808
13809
13810
13811
13812
|
procedure AuthenticationModel;
/// test the Email validation process
procedure EmailValidationProcess;
/// test the CQRS Repository for TUser persistence
procedure UserCQRSRepository;
end;
/// a test class, used by TTestServiceOrientedArchitecture
// - to test TPersistent objects used as parameters for remote service calls
TComplexNumber = class(TPersistent)
private
fReal: Double;
fImaginary: Double;
................................................................................
TPersonContactable.RegressionTests(self);
end;
procedure TTestDDDSharedUnits.UserCQRSRepository;
begin
TInfraRepoUserFactory.RegressionTests(self);
end;
{$endif DELPHI5OROLDER}
initialization
_uE0 := WinAnsiToUtf8(@UTF8_E0_F4_BYTES[0],1);
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
.....
13824
13825
13826
13827
13828
13829
13830
13831
13832
13833
13834
13835
13836
13837
13838
13839
13840
13841
13842
13843
13844
13845
13846
13847
13848
13849
13850
13851
13852
13853
13854
13855
13856
13857
13858
13859
13860
13861
13862
13863
13864
13865
13866
13867
13868
13869
13870
13871
13872
13873
13874
13875
13876
13877
13878
13879
13880
13881
13882
13883
13884
13885
13886
13887
13888
13889
13890
13891
13892
13893
13894
13895
13896
13897
13898
13899
13900
13901
13902
13903
13904
13905
13906
13907
13908
13909
13910
13911
13912
13913
13914
13915
13916
13917
13918
13919
13920
13921
13922
13923
13924
13925
13926
13927
13928
13929
13930
13931
13932
13933
13934
13935
13936
13937
13938
13939
13940
13941
13942
13943
13944
13945
13946
13947
13948
13949
13950
13951
13952
13953
13954
13955
13956
13957
13958
13959
13960
13961
13962
13963
13964
13965
13966
13967
13968
13969
13970
13971
13972
13973
13974
13975
13976
13977
13978
13979
13980
13981
13982
13983
13984
13985
13986
13987
13988
13989
13990
13991
13992
13993
13994
13995
13996
13997
13998
13999
14000
14001
14002
14003
14004
14005
14006
14007
14008
14009
14010
14011
14012
14013
14014
14015
14016
14017
14018
14019
14020
14021
14022
14023
14024
14025
14026
14027
14028
14029
14030
14031
14032
14033
14034
14035
14036
14037
14038
14039
14040
14041
14042
14043
14044
14045
14046
14047
14048
14049
14050
14051
14052
14053
14054
14055
14056
14057
14058
14059
14060
14061
14062
14063
14064
14065
14066
14067
14068
14069
14070
14071
14072
14073
14074
14075
14076
14077
14078
14079
14080
14081
14082
14083
14084
14085
14086
14087
14088
14089
14090
14091
14092
14093
14094
14095
14096
14097
14098
14099
14100
14101
14102
14103
14104
14105
14106
14107
14108
14109
14110
14111
14112
14113
14114
14115
14116
14117
14118
14119
14120
14121
14122
14123
14124
14125
14126
14127
14128
14129
14130
14131
14132
14133
14134
14135
14136
14137
14138
14139
14140
14141
14142
14143
14144
14145
14146
14147
|
procedure AuthenticationModel; /// test the Email validation process procedure EmailValidationProcess; /// test the CQRS Repository for TUser persistence procedure UserCQRSRepository; end; /// a test case for aggressive multi-threaded DDD ORM test TTestDDDMultiThread = class(TSynTestCase) private // Rest server fRestServer: TSQLRestServerDB; // Http server fHttpServer: TSQLHttpServer; /// Will create as many Clients as specified by aClient. // - Each client will perform as many Requests as specified by aRequests. // - This function will wait for all Clients until finished. function ClientTest(const aClients, aRequests: integer): boolean; protected /// Cleaning up the test procedure CleanUp; override; published /// Delete any old Test database on start procedure DeleteOldDatabase; /// Start the whole DDD Server (http and rest) procedure StartServer; /// Test straight-forward access using 1 thread and 1 client procedure SingleClientTest; /// Test concurrent access with multiple clients procedure MultiThreadedClientsTest; end; /// a test class, used by TTestServiceOrientedArchitecture // - to test TPersistent objects used as parameters for remote service calls TComplexNumber = class(TPersistent) private fReal: Double; fImaginary: Double; ................................................................................ TPersonContactable.RegressionTests(self); end; procedure TTestDDDSharedUnits.UserCQRSRepository; begin TInfraRepoUserFactory.RegressionTests(self); end; type // This is our simple Test data class. Will be mapped to TSQLRecordDDDTest. TDDDTest = class(TSynPersistent) private fDescription: RawUTF8; published property Description: RawUTF8 read fDescription write fDescription; end; TDDDTestObjArray = array of TDDDTest; // The corresponding TSQLRecord for TDDDTest. TSQLRecordDDDTest = class(TSQLRecord) private fDescription: RawUTF8; published property Description: RawUTF8 read fDescription write fDescription; end; // CQRS Query Interface fo TTest IDDDThreadsQuery = interface(ICQRSService) ['{DD402806-39C2-4921-98AA-A575DD1117D6}'] function SelectByDescription(const aDescription: RawUTF8): TCQRSResult; function SelectAll: TCQRSResult; function Get(out aAggregate: TDDDTest): TCQRSResult; function GetAll(out aAggregates: TDDDTestObjArray): TCQRSResult; function GetNext(out aAggregate: TDDDTest): TCQRSResult; function GetCount: integer; end; // CQRS Command Interface for TTest IDDDThreadsCommand = interface(IDDDThreadsQuery) ['{F0E4C64C-B43A-491B-85E9-FD136843BFCB}'] function Add(const aAggregate: TDDDTest): TCQRSResult; function Update(const aUpdatedAggregate: TDDDTest): TCQRSResult; function Delete: TCQRSResult; function DeleteAll: TCQRSResult; function Commit: TCQRSResult; function Rollback: TCQRSResult; end; // The infratructure REST class implementing the Query and Command Interfaces for TTest TDDDThreadsTestRest = class(TDDDRepositoryRestCommand, IDDDThreadsCommand) public function SelectByDescription(const aDescription: RawUTF8): TCQRSResult; function SelectAll: TCQRSResult; function Get(out aAggregate: TDDDTest): TCQRSResult; function GetAll(out aAggregates: TDDDTestObjArray): TCQRSResult; function GetNext(out aAggregate: TDDDTest): TCQRSResult; function Add(const aAggregate: TDDDTest): TCQRSResult; function Update(const aUpdatedAggregate: TDDDTest): TCQRSResult; end; // REST Factory for TDDDThreadsTestRest instances TDDDThreadsTestRestFactory = class(TDDDRepositoryRestFactory) public constructor Create(aRest: TSQLRest; aOwner: TDDDRepositoryRestManager = nil); reintroduce; end; // Custom TSQLHttpClient encapsulating the remote IDDDThreadsCommand interface. TDDDThreadsHttpClient = class(TSQLHttpClient) private // Internal Model fModel: TSQLModel; // IDDDThreadsCommand interface. Will be assigned inside SetUser fMyCommand: IDDDThreadsCommand; public constructor Create(const aServer, aPort: AnsiString); destructor Destroy; override; function SetUser(const aUserName, aPassword: RawUTF8; aHashedPassword: Boolean = false): boolean; reintroduce; property MyCommand: IDDDThreadsCommand read fMyCommand; end; // The thread used by TTestDDDMultiThread.ClientTest TDDDThreadsThread = class(TSynThread) private fHttpClient: TDDDThreadsHttpClient; fRequestCount: integer; fId: integer; fIsError: boolean; protected procedure Execute; override; public constructor Create(const aId, aRequestCount: integer); destructor Destroy; override; property IsError: boolean read fIsError; end; { TDDDThreadsTestRest } function TDDDThreadsTestRest.SelectByDescription(const aDescription: RawUTF8): TCQRSResult; begin result := ORMSelectOne('Description=?', [aDescription], (aDescription = '')); end; function TDDDThreadsTestRest.SelectAll: TCQRSResult; begin result := ORMSelectAll('', []); end; function TDDDThreadsTestRest.Get(out aAggregate: TDDDTest): TCQRSResult; begin result := ORMGetAggregate(aAggregate); end; function TDDDThreadsTestRest.GetAll(out aAggregates: TDDDTestObjArray): TCQRSResult; begin result := ORMGetAllAggregates(aAggregates); end; function TDDDThreadsTestRest.GetNext(out aAggregate: TDDDTest): TCQRSResult; begin result := ORMGetNextAggregate(aAggregate); end; function TDDDThreadsTestRest.Add(const aAggregate: TDDDTest): TCQRSResult; begin result := ORMAdd(aAggregate); end; function TDDDThreadsTestRest.Update(const aUpdatedAggregate: TDDDTest): TCQRSResult; begin result := ORMUpdate(aUpdatedAggregate); end; { TInfraRepoUserFactory } constructor TDDDThreadsTestRestFactory.Create(aRest: TSQLRest; aOwner: TDDDRepositoryRestManager); begin inherited Create(IDDDThreadsCommand, TDDDThreadsTestRest, TDDDTest, aRest, TSQLRecordDDDTest, aOwner); end; { TTestDDDMultiThread } procedure TTestDDDMultiThread.CleanUp; begin if Assigned(fHttpServer) then FreeAndNil(fHttpServer); if Assigned(fRestServer) then FreeAndNil(fRestServer); end; procedure TTestDDDMultiThread.DeleteOldDatabase; begin if FileExists(ChangeFileExt(ParamStr(0), '.db3')) then SysUtils.DeleteFile(ChangeFileExt(ParamStr(0), '.db3')); CheckNot(FileExists(ChangeFileExt(ParamStr(0), '.db3'))); end; procedure TTestDDDMultiThread.StartServer; begin fRestServer := TSQLRestServerDB.CreateWithOwnModel([TSQLRecordDDDTest], ChangeFileExt(ParamStr(0), '.db3'), true); with fRestServer do begin DB.Synchronous := smNormal; DB.LockingMode := lmExclusive; CreateMissingTables(); TInterfaceFactory.RegisterInterfaces([TypeInfo(IDDDThreadsQuery), TypeInfo(IDDDThreadsCommand)]); ServiceContainer.InjectResolver([TDDDThreadsTestRestFactory.Create(fRestServer)], true); ServiceDefine(TDDDThreadsTestRest, [IDDDThreadsCommand], sicClientDriven); end; fHttpServer := TSQLHttpServer.Create(HTTP_DEFAULTPORT, fRestServer, '+', {$ifdef ONLYUSEHTTPSOCKET}useHttpSocket{$else}useHttpApiRegisteringURI{$endif}); Check(fHttpServer.DBServerCount>0); end; procedure TTestDDDMultiThread.MultiThreadedClientsTest; begin ClientTest(20, 50); end; procedure TTestDDDMultiThread.SingleClientTest; var HttpClient: TDDDThreadsHttpClient; test: TDDDTest; i: integer; const MAX = 1000; begin HttpClient := TDDDThreadsHttpClient.Create('localhost', HTTP_DEFAULTPORT); try Check(HttpClient.SetUser('Admin', 'synopse')); test := TDDDTest.Create; try for i := 0 to MAX - 1 do begin test.Description := FormatUTF8('test-%', [i]); Check(HttpClient.MyCommand.Add(test) = cqrsSuccess); end; Check(HttpClient.MyCommand.Commit = cqrsSuccess); finally test.Free; end; finally HttpClient.Free; end; end; function TTestDDDMultiThread.ClientTest(const aClients, aRequests: integer): boolean; var i,count: integer; arrThreads: array of TDDDThreadsThread; arrHandles: array of THandle; rWait: Cardinal; begin result := false; count := fRestServer.TableRowCount(TSQLRecordDDDTest); SetLength(arrThreads, aClients); SetLength(arrHandles, aClients); for i := Low(arrThreads) to High(arrThreads) do begin arrThreads[i] := TDDDThreadsThread.Create(i, aRequests); {$ifdef MSWINDOWS} arrHandles[i] := arrThreads[i].Handle; {$endif} arrThreads[i].Start; end; try {$ifdef MSWINDOWS} repeat rWait := WaitForMultipleObjects(aClients, @arrHandles[0], True, INFINITE); until rWait <> WAIT_TIMEOUT; {$else} repeat Sleep(10); rWait := 0; for i := Low(arrThreads) to High(arrThreads) do if not arrThreads[i].Terminated then inc(rWait); until rWait=0; {$endif} finally for i := Low(arrThreads) to High(arrThreads) do begin CheckNot(arrThreads[i].IsError); arrThreads[i].Free; end; Check(fRestServer.TableRowCount(TSQLRecordDDDTest)=count+aClients*aRequests); end; end; { TDDDThreadsHttpClient } constructor TDDDThreadsHttpClient.Create(const aServer, aPort: AnsiString); begin fModel := TSQLModel.Create([TSQLRecordDDDTest]); fModel.Owner := self; inherited Create(aServer, aPort, fModel); end; destructor TDDDThreadsHttpClient.Destroy; begin fMyCommand := nil; inherited; end; function TDDDThreadsHttpClient.SetUser(const aUserName, aPassword: RawUTF8; aHashedPassword: Boolean = false): boolean; begin result := inherited SetUser(aUserName, aPassword, aHashedPassword); if result then begin ServiceDefine([IDDDThreadsCommand], sicClientDriven); Services.Resolve(IDDDThreadsCommand, fMyCommand); end; end; { TDDDThreadsThread } constructor TDDDThreadsThread.Create(const aID, aRequestCount: integer); begin inherited Create(true); fRequestCount := aRequestCount; fId := aId; fIsError := false; fHttpClient := TDDDThreadsHttpClient.Create('localhost', HTTP_DEFAULTPORT); fHttpClient.SetUser('Admin', 'synopse'); end; destructor TDDDThreadsThread.Destroy; begin fHttpClient.Free; inherited; end; procedure TDDDThreadsThread.Execute; var i: integer; test: TDDDTest; success: boolean; begin test := TDDDTest.Create; try success := true; for i := 0 to fRequestCount - 1 do begin test.Description := FormatUTF8('test-%-%', [fID, i]); success := success and (fHttpClient.MyCommand.Add(test) = cqrsSuccess); if not success then break; end; if success then success := fHttpClient.MyCommand.Commit = cqrsSuccess; if not success then begin fIsError := true; raise Exception.Create('Something went wrong!'); end; finally test.Free; Terminate; end; end; {$endif DELPHI5OROLDER} initialization _uE0 := WinAnsiToUtf8(@UTF8_E0_F4_BYTES[0],1); |
Changes to SynopseCommit.inc.
1 |
'1.18.1859'
|
| |
1 |
'1.18.1860'
|