dbdigest.pp 14 KB

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