digestanalyst.pas 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. unit digestanalyst;
  2. {$mode ObjFPC}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, teststr, testu, tresults, dbtests;
  6. Type
  7. // Program configuration
  8. TDigestConfig = record
  9. databasename: string;
  10. host: string;
  11. username: string;
  12. password: string;
  13. port: integer;
  14. testsrcdir: string;
  15. relsrcdir: string;
  16. verbose: string;
  17. sql: string;
  18. end;
  19. { TDBDigestAnalyzer }
  20. TDBDigestAnalyzer = Class(TObject)
  21. private
  22. FDB : TTestSQL;
  23. LongLogFile : TStrings;
  24. UnknownLines : integer;
  25. UseLongLog : Boolean;
  26. FCurLongLogLine : Integer;
  27. function CheckIDs(var aData: TTestRunData): Boolean;
  28. function GetExecuteLog(Line, FN: String): String;
  29. function GetIDs(const aConfig: TDigestConfig; var aData: TTestRunData): Boolean;
  30. procedure Processfile(const aFileName: String; var aData: TTestRunData);
  31. function SaveTestResult(aResult: TTestResultData): Boolean;
  32. procedure UpdateTestRun(const aData: TTestRunData);
  33. function GetContentsFromLongLog(Line: String): String;
  34. function GetLog(Line, FN: String): String;
  35. public
  36. constructor Create(aDB : TTestSQL);
  37. class function AnalyseLine(var Line: string; var Status: TTestStatus): Boolean;
  38. class procedure ExtractTestFileName(var Line: string);
  39. procedure Analyse(aConfig : TDigestConfig; aData : TTestRunData);
  40. end;
  41. implementation
  42. constructor TDBDigestAnalyzer.Create(aDB: TTestSQL);
  43. begin
  44. FDB:=aDB;
  45. end;
  46. function TDBDigestAnalyzer.CheckIDs(var aData : TTestRunData): Boolean;
  47. begin
  48. If aData.CategoryID=-1 then
  49. aData.CategoryID:=1;
  50. Result:=(aData.CPUID<>-1) and (aData.OSID<>-1) and (aData.VersionID<>-1);
  51. if Result then
  52. exit;
  53. If aData.CPUID=-1 then
  54. Verbose(V_Error,'NO ID for CPU "'+aData.CPU+'" found.');
  55. If aData.OSID=-1 then
  56. Verbose(V_Error,'NO ID for OS "'+aData.OS+'" found.');
  57. If aData.VersionID=-1 then
  58. Verbose(V_Error,'NO ID for version "'+aData.Version+'" found.');
  59. end;
  60. procedure TDBDigestAnalyzer.Analyse(aConfig: TDigestConfig; aData : TTestRunData);
  61. begin
  62. FDB.RelSrcDir:=aConfig.relsrcdir;
  63. FDB.TestSrcDir:=aConfig.testsrcdir;
  64. if (aData.longlogfile<>'') and FileExists(aData.longlogfile) then
  65. begin
  66. LongLogFile:=TStringList.Create;
  67. LongLogFile.LoadFromFile(aData.longlogfile);
  68. end;
  69. if not GetIDS(aConfig,aData) then
  70. exit;
  71. ProcessFile(aData.logfile,aData);
  72. UpdateTestRun(aData);
  73. end;
  74. function TDBDigestAnalyzer.GetIDs(const aConfig : TDigestConfig; var aData : TTestRunData): Boolean;
  75. begin
  76. Result := False;
  77. aData.CPUID := FDB.GetCPUID(aData.CPU);
  78. aData.OSID := FDB.GetOSID(aData.OS);
  79. aData.VersionID := FDB.GetVersionID(aData.Version);
  80. aData.CategoryID := FDB.GetCategoryID(aData.Category);
  81. aData.PlatformID := FDB.GetPlatformID(aData,True);
  82. If (Round(aData.Date)=0) then
  83. aData.Date:=Date;
  84. Result:=CheckIDS(aData);
  85. if not Result then
  86. Exit;
  87. aData.RunID:=FDB.GetRunID(aData);
  88. If (aData.RunID<>-1) then
  89. FDB.CleanTestRun(aData.RunID)
  90. else
  91. begin
  92. aData.RunID:=FDB.AddRun(aData);
  93. Result:=aData.RunID<>-1;
  94. if not Result then
  95. begin
  96. Verbose(V_Error,'Could not insert new testrun record!');
  97. exit;
  98. end;
  99. end;
  100. end;
  101. class procedure TDBDigestAnalyzer.ExtractTestFileName(var Line: string);
  102. Var I : integer;
  103. begin
  104. I:=Pos(' ',Line);
  105. If (I<>0) then
  106. Line:=Copy(Line,1,I-1);
  107. end;
  108. class function TDBDigestAnalyzer.AnalyseLine(var Line: string; var Status: TTestStatus): Boolean;
  109. Var
  110. TS : TTestStatus;
  111. begin
  112. Result:=False;
  113. For TS:=FirstStatus to LastStatus do
  114. begin
  115. Result:=Pos(StatusText[TS],Line)=1;
  116. If Result then
  117. begin
  118. Status:=TS;
  119. Delete(Line,1,Length(StatusText[TS]));
  120. ExtractTestFileName(Line);
  121. Break;
  122. end;
  123. end;
  124. end;
  125. (*
  126. ConfigAddStrings : Array [TConfigAddOpt] of string = (
  127. 'compilerdate',
  128. 'compilerfullversion',
  129. 'svncompilerrevision',
  130. 'svntestsrevision',
  131. 'svnrtlrevision',
  132. 'svnpackagesrevision'
  133. );
  134. ConfigAddCols : Array [TConfigAddOpt] of string = (
  135. 'TU_COMPILERDATE',
  136. 'TU_COMPILERFULLVERSION',
  137. 'TU_SVNCOMPILERREVISION',
  138. 'TU_SVNTESTSREVISION',
  139. 'TU_SVNRTLREVISION',
  140. 'TU_SVNPACKAGESREVISION'
  141. );
  142. *)
  143. const
  144. SeparationLine = '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>';
  145. function TDBDigestAnalyzer.GetContentsFromLongLog(Line: String): String;
  146. Function GetLongLogLine : String;
  147. begin
  148. Result:=LongLogFile[FCurLongLogLine];
  149. Inc(FCurLongLogLine);
  150. end;
  151. Function HaveLongLogLine : Boolean; inline;
  152. begin
  153. Result:=FCurLongLogLine<LongLogFile.Count;
  154. end;
  155. var
  156. S : String;
  157. IsFirst, IsFound : boolean;
  158. begin
  159. Result:='';
  160. IsFirst:=true;
  161. IsFound:=false;
  162. While HaveLongLogLine do
  163. begin
  164. S:=GetLongLogLine;
  165. if FCurLongLogLine=1 then
  166. begin
  167. { At start of file there is a separation line }
  168. if (pos(Line,S)=0) and (pos(SeparationLine,S)>=1) then
  169. S:=GetLongLogLine
  170. end;
  171. if pos(Line,S)=1 then
  172. begin
  173. IsFound:=true;
  174. while HaveLongLogLine do
  175. begin
  176. S:=GetLongLogLine;
  177. { End of file marker }
  178. if (Not HaveLongLogLine) or (pos(SeparationLine,S)=1) then
  179. exit;
  180. if length(Result)<MaxLogSize then
  181. Result:=Result+S+LineEnding;
  182. if pos(SeparationLine,S)>1 then
  183. exit;
  184. end;
  185. end
  186. else if IsFirst then
  187. begin
  188. Verbose(V_Warning,'Line "'+Line+'" not found as next "'+S+'"');
  189. IsFirst:=false;
  190. end;
  191. end;
  192. if not IsFound then
  193. begin
  194. Verbose(V_Warning,'Line "'+Line+'" not found');
  195. FCurlongLogLine:=0; // Reset
  196. end;
  197. end;
  198. function TDBDigestAnalyzer.GetLog(Line, FN: String): String;
  199. begin
  200. if UseLongLog then
  201. begin
  202. Result:=GetContentsFromLongLog(Line);
  203. exit;
  204. end;
  205. FN:=ChangeFileExt(FN,'.log');
  206. { packages tests have ../ replaced by root/ }
  207. if not FileExists(FN) and (Copy(FN,1,3)='../') then
  208. FN:='root/'+Copy(FN,4,length(FN));
  209. If FileExists(FN) then
  210. Result:=GetFileContents(FN)
  211. else
  212. begin
  213. Verbose(V_Warning,'File "'+FN+'" not found');
  214. Result:='';
  215. end;
  216. end;
  217. function TDBDigestAnalyzer.GetExecuteLog(Line, FN: String): String;
  218. begin
  219. if UseLongLog then
  220. begin
  221. Result:=GetContentsFromLongLog(Line);
  222. exit;
  223. end;
  224. FN:=ChangeFileExt(FN,'.elg');
  225. { packages tests have ../ replaced by root/ }
  226. if not FileExists(FN) and (Copy(FN,1,3)='../') then
  227. FN:='root/'+Copy(FN,4,length(FN));
  228. If FileExists(FN) then
  229. Result:=GetFileContents(FN)
  230. else
  231. begin
  232. Verbose(V_Warning,'File "'+FN+'" not found');
  233. Result:='';
  234. end;
  235. end;
  236. function TDBDigestAnalyzer.SaveTestResult(aResult : TTestResultData) : Boolean;
  237. var
  238. lLast : TTestResultData;
  239. lNewID : Int64;
  240. begin
  241. lLast:=FDB.GetLastTestResult(aResult.TestID,aResult.PlatformID);
  242. if aResult.Differs(lLast) then
  243. begin
  244. // Need to save
  245. lNewID:=FDB.AddTestResult(aResult)
  246. end
  247. else
  248. // Update status, testrun & log
  249. FDB.UpdateTestResult(aResult);
  250. end;
  251. procedure TDBDigestAnalyzer.Processfile(const aFileName: String; var aData: TTestRunData);
  252. var
  253. logfile : TStrings;
  254. fullline,line,prevLine : string;
  255. TS : TTestStatus;
  256. Testlog : string;
  257. count_test : boolean;
  258. lPrev,lResult : TTestResultData;
  259. begin
  260. lPrev:=Default(TTestResultData);
  261. // init data common to the whole testrun
  262. lResult.RunID:=aData.RunID;
  263. lResult.PlatFormID:=aData.PlatFormID;
  264. lPrev.RunID:=aData.RunID;
  265. lPrev.PlatformID:=aData.PlatformID;
  266. lPrev.TestID:=-1; // Init no test
  267. PrevLine:='';
  268. logfile:=TStringList.Create;
  269. try
  270. LogFile.Capacity:=20000;
  271. LogFile.LoadFromFile(aFileName);
  272. For FullLine in LogFile do
  273. begin
  274. lResult:=Default(TTestResultData);
  275. line:=fullline;
  276. lResult.TestResult:=stFailedToCompile;
  277. If not AnalyseLine(line,TS) then
  278. begin
  279. Inc(UnknownLines);
  280. Verbose(V_Warning,'Unknown line: "'+line+'"');
  281. end
  282. else
  283. begin
  284. Verbose(V_NORMAL,'Analysing result for test '+Line);
  285. lResult.TestID:=FDB.RequireTestID(line);
  286. if lResult.TestID=-1 then
  287. begin
  288. Verbose(V_Warning,'No test ID: "'+line+'", skipping');
  289. Continue;
  290. end;
  291. If ExpectRun[TS] then
  292. begin
  293. // We expect a log line with log result, save
  294. Inc(aData.StatusCount[TS]);
  295. lPrev.TestResult:=TS;
  296. lPrev.TestID:=lResult.TestID;
  297. PrevLine:=line;
  298. end
  299. else
  300. begin
  301. // New test, insert previous result
  302. if (lPrev.TestID<>-1) and (lPrev.TestID<>lResult.TestID) then
  303. begin
  304. { This can only happen if a Successfully compiled message
  305. is not followed by any other line about the same test }
  306. SaveTestResult(lPrev);
  307. Verbose(V_Warning,'Orphaned test: "'+prevline+'"');
  308. end;
  309. // same test, so now we have run result
  310. lPrev.TestID:=-1;
  311. lResult.TestResult:=TS;
  312. If (lResult.TestID<>-1) then
  313. begin
  314. If Not (TestOK[TS] or TestSkipped[TS]) then
  315. begin
  316. lResult.Log:=GetExecuteLog(Fullline,Line);
  317. if pos(failed_to_compile,lResult.Log)=1 then
  318. lResult.Log:=GetLog(Fullline,Line);
  319. end
  320. else
  321. lResult.Log:='';
  322. SaveTestResult(lResult);
  323. end;
  324. end
  325. end
  326. end;
  327. finally
  328. Logfile.Free;
  329. end;
  330. end;
  331. procedure TDBDigestAnalyzer.UpdateTestRun(const aData : TTestRunData);
  332. begin
  333. FDB.UpdateTestRun(aData);
  334. end;
  335. end.