dbdigest.pp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. {
  2. This file is part of the Free Pascal test suite.
  3. Copyright (c) 2002 by the Free Pascal development team.
  4. This program generates a digest
  5. of the last tests run.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$mode objfpc}
  13. {$h+}
  14. {$linklib pthread}
  15. program digest;
  16. uses
  17. sysutils,teststr,testu,tresults,dbtests;
  18. Var
  19. StatusCount : Array[TTestStatus] of Integer;
  20. UnknownLines : integer;
  21. Procedure ExtractTestFileName(Var Line : string);
  22. Var I : integer;
  23. begin
  24. I:=Pos(' ',Line);
  25. If (I<>0) then
  26. Line:=Copy(Line,1,I-1);
  27. end;
  28. Function Analyse(Var Line : string; Var Status : TTestStatus) : Boolean;
  29. Var
  30. TS : TTestStatus;
  31. begin
  32. Result:=False;
  33. For TS:=FirstStatus to LastStatus do
  34. begin
  35. Result:=Pos(StatusText[TS],Line)=1;
  36. If Result then
  37. begin
  38. Status:=TS;
  39. Delete(Line,1,Length(StatusText[TS]));
  40. ExtractTestFileName(Line);
  41. Break;
  42. end;
  43. end;
  44. end;
  45. Type
  46. TConfigOpt = (
  47. coDatabaseName,
  48. soHost,
  49. coUserName,
  50. coPassword,
  51. coPort,
  52. coLogFile,
  53. coLongLogFile,
  54. coOS,
  55. coCPU,
  56. coCategory,
  57. coVersion,
  58. coDate,
  59. coSubmitter,
  60. coMachine,
  61. coComment,
  62. coTestSrcDir,
  63. coRelSrcDir,
  64. coVerbose
  65. );
  66. { Additional options only for dbdigest.cfg file }
  67. TConfigAddOpt = (
  68. coCompilerDate,
  69. coCompilerFullVersion,
  70. coSvnCompilerRevision,
  71. coSvnTestsRevision,
  72. coSvnRTLRevision,
  73. coSvnPackagesRevision
  74. );
  75. Const
  76. ConfigStrings : Array [TConfigOpt] of string = (
  77. 'databasename',
  78. 'host',
  79. 'username',
  80. 'password',
  81. 'port',
  82. 'logfile',
  83. 'longlogfile',
  84. 'os',
  85. 'cpu',
  86. 'category',
  87. 'version',
  88. 'date',
  89. 'submitter',
  90. 'machine',
  91. 'comment',
  92. 'testsrcdir',
  93. 'relsrcdir',
  94. 'verbose'
  95. );
  96. ConfigAddStrings : Array [TConfigAddOpt] of string = (
  97. 'compilerdate',
  98. 'compilerfullversion',
  99. 'svncompilerrevision',
  100. 'svntestsrevision',
  101. 'svnrtlrevision',
  102. 'svnpackagesrevision'
  103. );
  104. ConfigAddCols : Array [TConfigAddOpt] of string = (
  105. 'TU_COMPILERDATE',
  106. 'TU_COMPILERFULLVERSION',
  107. 'TU_SVNCOMPILERREVISION',
  108. 'TU_SVNTESTSREVISION',
  109. 'TU_SVNRTLREVISION',
  110. 'TU_SVNPACKAGESREVISION'
  111. );
  112. ConfigOpts : Array[TConfigOpt] of char
  113. = ('d','h','u','p','P','l','L','o','c','a','v','t','s','m','C','S','r','V');
  114. Var
  115. TestOS,
  116. TestCPU,
  117. TestVersion,
  118. TestCategory,
  119. DatabaseName,
  120. HostName,
  121. UserName,
  122. Password,
  123. Port,
  124. LongLogFileName,
  125. LogFileName,
  126. Submitter,
  127. Machine,
  128. Comment : String;
  129. TestDate : TDateTime;
  130. TestCompilerDate,
  131. TestCompilerFullVersion,
  132. TestSvnCompilerRevision,
  133. TestSvnTestsRevision,
  134. TestSvnRTLRevision,
  135. TestSvnPackagesRevision : String;
  136. Procedure SetAddOpt (O : TConfigAddOpt; Value : string);
  137. begin
  138. Case O of
  139. coCompilerDate:
  140. TestCompilerDate:=Value;
  141. coCompilerFullVersion:
  142. TestCompilerFullVersion:=Value;
  143. coSvnCompilerRevision:
  144. TestSvnCompilerRevision:=Value;
  145. coSvnTestsRevision:
  146. TestSvnTestsRevision:=Value;
  147. coSvnRTLRevision:
  148. TestSvnRTLRevision:=Value;
  149. coSvnPackagesRevision:
  150. TestSvnPackagesRevision:=Value;
  151. end;
  152. end;
  153. Procedure SetOpt (O : TConfigOpt; Value : string);
  154. var
  155. year,month,day,min,hour : word;
  156. begin
  157. Case O of
  158. coDatabaseName : DatabaseName:=Value;
  159. soHost : HostName:=Value;
  160. coUserName : UserName:=Value;
  161. coPassword : Password:=Value;
  162. coPort : Port:=Value;
  163. coLogFile : LogFileName:=Value;
  164. coLongLogFile : LongLogFileName:=Value;
  165. coOS : TestOS:=Value;
  166. coCPU : TestCPU:=Value;
  167. coCategory : TestCategory:=Value;
  168. coVersion : TestVersion:=Value;
  169. coDate :
  170. begin
  171. { Formated like YYYYMMDDhhmm }
  172. if Length(value)=12 then
  173. begin
  174. year:=StrToInt(Copy(value,1,4));
  175. month:=StrToInt(Copy(value,5,2));
  176. day:=StrToInt(Copy(Value,7,2));
  177. hour:=StrToInt(Copy(Value,9,2));
  178. min:=StrToInt(Copy(Value,11,2));
  179. TestDate:=EncodeDate(year,month,day)+EncodeTime(hour,min,0,0);
  180. end
  181. else
  182. Verbose(V_Error,'Error in date format, use YYYYMMDDhhmm');
  183. end;
  184. coSubmitter : Submitter:=Value;
  185. coMachine : Machine:=Value;
  186. coComment : Comment:=Value;
  187. coVerbose : DoVerbose:=true;
  188. coTestSrcDir :
  189. begin
  190. TestSrcDir:=Value;
  191. if (TestSrcDir<>'') and (TestSrcDir[length(TestSrcDir)]<>'/') then
  192. TestSrcDir:=TestSrcDir+'/';
  193. end;
  194. coRelSrcDir :
  195. begin
  196. RelSrcDir:=Value;
  197. if (RelSrcDir<>'') and (RelSrcDir[length(RelSrcDir)]<>'/') then
  198. RelSrcDir:=RelSrcDir+'/';
  199. if (RelSrcDir<>'') and (RelSrcDir[1]='/') then
  200. RelSrcDir:=copy(RelSrcDir,2,length(RelSrcDir)-1);
  201. end;
  202. end;
  203. end;
  204. Function ProcessOption(S: String) : Boolean;
  205. Var
  206. N : String;
  207. I : Integer;
  208. co : TConfigOpt;
  209. coa : TConfigAddOpt;
  210. begin
  211. Verbose(V_DEBUG,'Processing option: '+S);
  212. I:=Pos('=',S);
  213. Result:=(I<>0);
  214. If Result then
  215. begin
  216. N:=Copy(S,1,I-1);
  217. Delete(S,1,I);
  218. For co:=low(TConfigOpt) to high(TConfigOpt) do
  219. begin
  220. Result:=CompareText(ConfigStrings[co],N)=0;
  221. If Result then
  222. begin
  223. SetOpt(co,S);
  224. Exit;
  225. end;
  226. end;
  227. For coa:=low(TConfigAddOpt) to high(TConfigAddOpt) do
  228. begin
  229. Result:=CompareText(ConfigAddStrings[coa],N)=0;
  230. If Result then
  231. begin
  232. SetAddOpt(coa,S);
  233. Exit;
  234. end;
  235. end;
  236. end;
  237. Verbose(V_ERROR,'Unknown option : '+n+S);
  238. end;
  239. Procedure ProcessConfigfile(FN : String);
  240. Var
  241. F : Text;
  242. S : String;
  243. I : Integer;
  244. begin
  245. // Set the default value for old digests without RelSrcDir to the rtl/compiler
  246. // testsuite
  247. RelSrcDir:='tests/';
  248. If Not FileExists(FN) Then
  249. Exit;
  250. Verbose(V_DEBUG,'Parsing config file: '+FN);
  251. Assign(F,FN);
  252. {$i-}
  253. Reset(F);
  254. If IOResult<>0 then
  255. Exit;
  256. {$I+}
  257. While not(EOF(F)) do
  258. begin
  259. ReadLn(F,S);
  260. S:=trim(S);
  261. I:=Pos('#',S);
  262. If I<>0 then
  263. S:=Copy(S,1,I-1);
  264. If (S<>'') then
  265. ProcessOption(S);
  266. end;
  267. Close(F);
  268. end;
  269. Procedure ProcessCommandLine;
  270. Var
  271. I : Integer;
  272. O : String;
  273. c,co : TConfigOpt;
  274. Found : Boolean;
  275. begin
  276. I:=1;
  277. While I<=ParamCount do
  278. begin
  279. O:=Paramstr(I);
  280. Found:=Length(O)=2;
  281. If Found then
  282. For co:=low(TConfigOpt) to high(TConfigOpt) do
  283. begin
  284. Found:=(O[2]=ConfigOpts[co]);
  285. If Found then
  286. begin
  287. c:=co;
  288. Break;
  289. end;
  290. end;
  291. If Not Found then
  292. Verbose(V_ERROR,'Illegal command-line option : '+O)
  293. else
  294. begin
  295. Found:=(I<ParamCount);
  296. If Not found then
  297. Verbose(V_ERROR,'Option requires argument : '+O)
  298. else
  299. begin
  300. inc(I);
  301. O:=Paramstr(I);
  302. SetOpt(c,o);
  303. end;
  304. end;
  305. Inc(I);
  306. end;
  307. end;
  308. Var
  309. TestCPUID : Integer;
  310. TestOSID : Integer;
  311. TestVersionID : Integer;
  312. TestCategoryID : Integer;
  313. TestRunID : Integer;
  314. Procedure GetIDs;
  315. begin
  316. TestCPUID := GetCPUId(TestCPU);
  317. If TestCPUID=-1 then
  318. Verbose(V_Error,'NO ID for CPU "'+TestCPU+'" found.');
  319. TestOSID := GetOSID(TestOS);
  320. If TestOSID=-1 then
  321. Verbose(V_Error,'NO ID for OS "'+TestOS+'" found.');
  322. TestCategoryID := GetCategoryID(TestCategory);
  323. If TestCategoryID=-1 then
  324. begin
  325. // Verbose(V_Error,'NO ID for Category "'+TestCategory+'" found.');
  326. TestCategoryID:=1;
  327. end;
  328. TestVersionID := GetVersionID(TestVersion);
  329. If TestVersionID=-1 then
  330. Verbose(V_Error,'NO ID for version "'+TestVersion+'" found.');
  331. If (Round(TestDate)=0) then
  332. Testdate:=Now;
  333. TestRunID:=GetRunID(TestOSID,TestCPUID,TestVersionID,TestDate);
  334. If (TestRunID=-1) then
  335. begin
  336. TestRunID:=AddRun(TestOSID,TestCPUID,TestVersionID,TestCategoryID,TestDate);
  337. If TestRUnID=-1 then
  338. Verbose(V_Error,'Could not insert new testrun record!');
  339. end
  340. else
  341. CleanTestRun(TestRunID);
  342. end;
  343. var
  344. LongLogFile : Text;
  345. const
  346. UseLongLog : boolean = false;
  347. Function GetContentsFromLongLog(Line : String) : String;
  348. var
  349. S : String;
  350. IsFirst, IsFound : boolean;
  351. begin
  352. Result:='';
  353. IsFirst:=true;
  354. IsFound:=false;
  355. While Not(EOF(LongLogFile)) do
  356. begin
  357. ReadLn(LongLogFile,S);
  358. if pos(Line,S)=1 then
  359. begin
  360. IsFound:=true;
  361. while not eof(LongLogFile) do
  362. begin
  363. ReadLn(LongLogFile,S);
  364. { End of file marker }
  365. if eof(LongLogFile) or (pos('>>>>>>>>>>>',S)=1) then
  366. exit;
  367. Result:=Result+S+LineEnding;
  368. end;
  369. end
  370. else if IsFirst then
  371. begin
  372. Verbose(V_Warning,'Line "'+Line+'" not found as next "'+S+'"');
  373. IsFirst:=false;
  374. end;
  375. end;
  376. if not IsFound then
  377. begin
  378. Verbose(V_Warning,'Line "'+Line+'" not found');
  379. { Restart to get a chance to find others }
  380. if eof(LongLogFile) then
  381. begin
  382. Close(LongLogFile);
  383. Reset(LongLogFile);
  384. end;
  385. end;
  386. end;
  387. Function GetLog(Line, FN : String) : String;
  388. begin
  389. if UseLongLog then
  390. begin
  391. Result:=GetContentsFromLongLog(Line);
  392. exit;
  393. end;
  394. FN:=ChangeFileExt(FN,'.log');
  395. If FileExists(FN) then
  396. Result:=GetFileContents(FN)
  397. else
  398. Result:='';
  399. end;
  400. Function GetExecuteLog(Line, FN : String) : String;
  401. begin
  402. if UseLongLog then
  403. begin
  404. Result:=GetContentsFromLongLog(Line);
  405. exit;
  406. end;
  407. FN:=ChangeFileExt(FN,'.elg');
  408. If FileExists(FN) then
  409. Result:=GetFileContents(FN)
  410. else
  411. Result:='';
  412. end;
  413. Procedure Processfile (FN: String);
  414. var
  415. logfile : text;
  416. fullline,line,prevLine : string;
  417. TS,PrevTS : TTestStatus;
  418. ID,PrevID : integer;
  419. Testlog : string;
  420. is_new : boolean;
  421. begin
  422. Assign(logfile,FN);
  423. PrevId:=-1;
  424. PrevLine:='';
  425. is_new:=false;
  426. PrevTS:=low(TTestStatus);
  427. {$i-}
  428. reset(logfile);
  429. if ioresult<>0 then
  430. Verbose(V_Error,'Unable to open log file'+FN);
  431. {$i+}
  432. while not eof(logfile) do
  433. begin
  434. readln(logfile,line);
  435. fullline:=line;
  436. If analyse(line,TS) then
  437. begin
  438. Verbose(V_NORMAL,'Analysing result for test '+Line);
  439. If Not ExpectRun[TS] then
  440. begin
  441. ID:=RequireTestID(Line);
  442. if (PrevID<>-1) and (PrevID<>ID) then
  443. begin
  444. { This can only happen if a Successfully compiled message
  445. is not followed by any other line about the same test }
  446. TestLog:='';
  447. AddTestResult(PrevID,TestRunId,ord(PrevTS),
  448. TestOK[PrevTS],TestSkipped[PrevTS],TestLog,is_new);
  449. Verbose(V_Warning,'Orphaned test: "'+prevline+'"');
  450. end;
  451. PrevID:=-1;
  452. If (ID<>-1) then
  453. begin
  454. If Not (TestOK[TS] or TestSkipped[TS]) then
  455. begin
  456. TestLog:=GetExecuteLog(Fullline,Line);
  457. if pos(failed_to_compile,TestLog)=1 then
  458. TestLog:=GetLog(Fullline,Line);
  459. end
  460. else
  461. TestLog:='';
  462. { AddTestResult can fail for test that contain %recompile
  463. as the same }
  464. if AddTestResult(ID,TestRunID,Ord(TS),TestOK[TS],
  465. TestSkipped[TS],TestLog,is_new) <> -1 then
  466. begin
  467. if is_new then
  468. Inc(StatusCount[TS])
  469. else
  470. Verbose(V_Debug,'Test: "'+line+'" was updated');
  471. end
  472. else
  473. begin
  474. Verbose(V_Warning,'Test: "'+line+'" already registered');
  475. end;
  476. end;
  477. end
  478. else
  479. begin
  480. Inc(StatusCount[TS]);
  481. PrevTS:=TS;
  482. PrevID:=RequireTestID(line);
  483. PrevLine:=line;
  484. end;
  485. end
  486. else
  487. begin
  488. Inc(UnknownLines);
  489. Verbose(V_Warning,'Unknown line: "'+line+'"');
  490. end;
  491. end;
  492. close(logfile);
  493. end;
  494. procedure UpdateTestRun;
  495. var
  496. i : TTestStatus;
  497. qry : string;
  498. res : TQueryResult;
  499. begin
  500. qry:='UPDATE TESTRUN SET ';
  501. for i:=low(TTestStatus) to high(TTestStatus) do
  502. qry:=qry+format('%s=%d, ',[SQLField[i],StatusCount[i]]);
  503. if TestCompilerDate<>'' then
  504. qry:=qry+format('%s="%s", ',[ConfigAddCols[coCompilerDate],EscapeSQL(TestCompilerDate)]);
  505. if TestCompilerFullVersion<>'' then
  506. qry:=qry+format('%s="%s", ',[ConfigAddCols[coCompilerFullVersion],EscapeSQL(TestCompilerFullVersion)]);
  507. if TestSvnCompilerRevision<>'' then
  508. qry:=qry+format('%s="%s", ',[ConfigAddCols[coSvnCompilerRevision],EscapeSQL(TestSvnCompilerRevision)]);
  509. if TestSvnTestsRevision<>'' then
  510. qry:=qry+format('%s="%s", ',[ConfigAddCols[coSvnTestsRevision],EscapeSQL(TestSvnTestsRevision)]);
  511. if TestSvnRTLRevision<>'' then
  512. qry:=qry+format('%s="%s", ',[ConfigAddCols[coSvnRTLRevision],EscapeSQL(TestSvnRTLRevision)]);
  513. if TestSvnPackagesRevision<>'' then
  514. qry:=qry+format('%s="%s", ',[ConfigAddCols[coSvnPackagesRevision],EscapeSQL(TestSvnPackagesRevision)]);
  515. qry:=qry+format('TU_SUBMITTER="%s", TU_MACHINE="%s", TU_COMMENT="%s", TU_DATE="%s"',[Submitter,Machine,Comment,SqlDate(TestDate)]);
  516. qry:=qry+' WHERE TU_ID='+format('%d',[TestRunID]);
  517. RunQuery(Qry,res)
  518. end;
  519. begin
  520. ProcessConfigFile('dbdigest.cfg');
  521. ProcessCommandLine;
  522. If LogFileName<>'' then
  523. begin
  524. ConnectToDatabase(DatabaseName,HostName,UserName,Password,Port);
  525. if LongLogFileName<>'' then
  526. begin
  527. {$I-}
  528. Assign(LongLogFile,LongLogFileName);
  529. Reset(LongLogFile);
  530. If IOResult=0 then
  531. UseLongLog:=true;
  532. {$I+}
  533. end;
  534. GetIDs;
  535. ProcessFile(LogFileName);
  536. UpdateTestRun;
  537. if UseLongLog then
  538. Close(LongLogFile);
  539. end
  540. else
  541. Verbose(V_ERROR,'Missing log file name');
  542. end.