unit ProbeReport; {$mode objfpc}{$H+}{$codepage utf8} interface uses SysUtils, fpjson; type TProbeReport = class private FRoot: TJSONObject; FTests: TJSONArray; public constructor Create; destructor Destroy; override; procedure Add(const Id, Status, Detail: string); procedure Check(const Id: string; const Ok: Boolean; const Detail: string); procedure Save(const FileName: string); function Status: string; property Root: TJSONObject read FRoot; end; implementation uses Classes, CastleLog, ProbeBuild; constructor TProbeReport.Create; begin inherited; FRoot := TJSONObject.Create; FRoot.Add('schema', 'kam-android-runtime/1'); FRoot.Add('build_id', ProbeBuildId); FRoot.Add('profile', ProbeProfile); FRoot.Add('cpu_expected', ProbeCpu); FRoot.Add('upstream_commit', ProbeUpstreamCommit); FRoot.Add('scope', 'Android architecture smoke, not a running KaM world'); FRoot.Add('world_simulation', 'NOT_RUN'); FTests := TJSONArray.Create; FRoot.Add('tests', FTests); end; destructor TProbeReport.Destroy; begin FRoot.Free; inherited; end; procedure TProbeReport.Add(const Id, Status, Detail: string); var J: TJSONObject; I: Integer; begin for I := FTests.Count - 1 downto 0 do if FTests.Objects[I].Get('id', '') = Id then FTests.Delete(I); J := TJSONObject.Create; J.Add('id', Id); J.Add('status', Status); J.Add('detail', Detail); FTests.Add(J); WritelnLog('KaMProbe', Id + ': ' + Status + ' ' + Detail); end; procedure TProbeReport.Check(const Id: string; const Ok: Boolean; const Detail: string); begin if Ok then Add(Id, 'PASS', Detail) else Add(Id, 'FAIL', Detail); end; function TProbeReport.Status: string; var I: Integer; begin Result := 'PASS'; for I := 0 to FTests.Count - 1 do if FTests.Objects[I].Get('status','') = 'FAIL' then Exit('FAIL'); { Optional NOT_RUN / OBSERVED rows do not make the automatic smoke fail. They remain visible; PASS applies only to executed automatic checks. } end; procedure TProbeReport.Save(const FileName: string); var S: TStringList; begin FRoot.Delete('automatic_smoke_status'); FRoot.Add('automatic_smoke_status', Status); if not ForceDirectories(ExtractFileDir(FileName)) then raise Exception.Create('Cannot create report directory'); S := TStringList.Create; try S.Text := FRoot.FormatJSON; { Evidence must not depend on the filesystem behaviour measured separately by decision.persistence.rename_replace. } S.SaveToFile(FileName); finally S.Free; end; end; end.