Skip to content

Commit

Permalink
reviews
Browse files Browse the repository at this point in the history
  • Loading branch information
rbenyoussef committed Mar 20, 2024
1 parent 562f39d commit 413eb27
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 128 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,13 @@
import com.chutneytesting.campaign.domain.CampaignExecutionRepository;
import com.chutneytesting.campaign.domain.CampaignRepository;
import com.chutneytesting.campaign.domain.CampaignService;
import com.chutneytesting.execution.domain.campaign.CampaignExecutionEngine;
import com.chutneytesting.scenario.api.raw.dto.TestCaseIndexDto;
import com.chutneytesting.scenario.infra.TestCaseRepositoryAggregator;
import com.chutneytesting.server.core.domain.execution.history.ExecutionHistory;
import com.chutneytesting.server.core.domain.execution.history.ExecutionHistoryRepository;
import com.chutneytesting.server.core.domain.scenario.ScenarioNotFoundException;
import com.chutneytesting.server.core.domain.scenario.campaign.Campaign;
import com.chutneytesting.server.core.domain.scenario.campaign.CampaignExecution;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -106,13 +104,11 @@ public CampaignDto getCampaignById(@PathVariable("campaignId") Long campaignId)
@PreAuthorize("hasAuthority('CAMPAIGN_READ')")
@GetMapping(path = "/execution/{campaignExecutionId}", produces = MediaType.APPLICATION_JSON_VALUE)
public CampaignExecutionFullReportDto getCampaignExecutionReportById(@PathVariable("campaignExecutionId") Long campaignExecutionId) {
List<ExecutionHistory.Execution> executions = new ArrayList<>();

CampaignExecution campaignExecution = campaignExecutionRepository.getCampaignExecutionById(campaignExecutionId);

campaignExecution.scenarioExecutionReports().forEach(scenarioExecutionCampaign -> {
executions.add(executionHistoryRepository.getExecution(scenarioExecutionCampaign.scenarioId, scenarioExecutionCampaign.execution.executionId()));
});
List<ExecutionHistory.Execution> executions = campaignExecution.scenarioExecutionReports().stream()
.map(ser -> executionHistoryRepository.getExecution(ser.scenarioId, ser.execution.executionId()))
.toList();

return CampaignExecutionReportMapper.fullExecutionToDto(campaignExecution, executions);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ private static Object[] securedEndPointList() {
{POST, "/api/ui/campaign/execution/v1/666/stop", "CAMPAIGN_EXECUTE", "{}", NOT_FOUND},
{GET, "/api/ui/campaign/execution/v1/byID/666", "CAMPAIGN_EXECUTE", null, NOT_FOUND},
{GET, "/api/ui/campaign/execution/v1/byID/666/DEFAULT", "CAMPAIGN_EXECUTE", null, NOT_FOUND},
{GET, "/api/ui/campaign/v1/execution/1", "CAMPAIGN_READ", null, NOT_FOUND},

{GET, "/api/v1/editions/testcases/testcaseId", "SCENARIO_READ", null, OK},
{POST, "/api/v1/editions/testcases/testcaseId", "SCENARIO_WRITE", "{}", NOT_FOUND},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

import { ScenarioExecutionReportOutline } from '.';
import { Execution, ScenarioExecutionReport } from '../scenario';
import { Execution } from '../scenario';
import { ExecutionStatus } from '../scenario/execution-status';

export interface CampaignExecutionReport {
Expand Down Expand Up @@ -76,7 +76,7 @@ export class CampaignReport {
var notExecuted = 0;
var pauses = 0;
report.scenarioExecutionReports.forEach(r => {
switch(r.status) {
switch (r.status) {
case ExecutionStatus.NOT_EXECUTED:
notExecuted++;
break;
Expand Down Expand Up @@ -141,7 +141,7 @@ export class CampaignReport {
}

refresh(campaignReport: CampaignReport) {
if(campaignReport.report.campaignId === this.report.campaignId && campaignReport.report.executionId === this.report.executionId){
if (campaignReport.report.campaignId === this.report.campaignId && campaignReport.report.executionId === this.report.executionId) {
this.report = campaignReport.report;
this.notexecuted = campaignReport.notexecuted;
this.running = campaignReport.running;
Expand Down
7 changes: 4 additions & 3 deletions chutney/ui/src/app/core/model/scenario/execution.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
*/

import { ExecutionStatus } from '@core/model/scenario/execution-status';
import { Campaign, CampaignExecutionReport } from '@core/model';
import { CampaignExecutionReport } from '@core/model';

export class Execution {

public static NO_EXECUTION: Execution = new Execution(null, null, null, null, null, null, null);
public static NO_EXECUTION: Execution = new Execution(null, null, null, null, null, null, null, null);

constructor(
public duration: number,
Expand All @@ -29,11 +29,11 @@ export class Execution {
public time: Date,
public environment: string,
public user: string,
public testCaseTitle: string,
public info?: string,
public error?: string,
public scenarioId?: string,
public campaignReport?: CampaignExecutionReport,
public testCaseTitle?: string
) { }

static deserializeExecutions(jsonObject: any): Execution[] {
Expand All @@ -49,6 +49,7 @@ export class Execution {
new Date(jsonObject.time),
jsonObject.environment,
jsonObject.user,
jsonObject.testCaseTitle,
jsonObject.info,
jsonObject.error,
jsonObject.scenarioId,
Expand Down
151 changes: 151 additions & 0 deletions chutney/ui/src/app/core/services/campaign-report.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/**
* Copyright 2017-2023 Enedis
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { Injectable } from "@angular/core";
import { CampaignExecutionFullReport, ScenarioExecutionReport, StepExecutionReport } from "@core/model";
import { ExecutionStatus } from "@core/model/scenario/execution-status";
import { TranslateService } from "@ngx-translate/core";
import { DurationPipe } from "@shared/pipes";
import jsPDF from "jspdf";
import autoTable, { CellHookData } from "jspdf-autotable";

@Injectable({
providedIn: 'root'
})
export class CampaignReportService {

constructor(private translate: TranslateService) {
}

public toPDF(report: CampaignExecutionFullReport): jsPDF {

const pdf = new jsPDF('landscape');

this.campaignSummaryGeneration(pdf, report);
pdf.addPage();
this.scenariiSummaryGeneration(pdf, report);

return pdf;
}

private campaignSummaryGeneration(pdf: jsPDF, report: CampaignExecutionFullReport) {
const url = location.origin + '/#/scenario/:id/executions??open=:executionId&active=:executionId';
const duration = new DurationPipe();
const pdfFontSize = pdf.getFontSize();
const docTitle = report.campaignName;
pdf.text(docTitle, 148, 20, { align: 'center' });

const passedScenarioExecutionCount = report.scenarioExecutionReports.filter(s => s.status === ExecutionStatus.SUCCESS).length;
const totalscenarioExecutionCount = report.scenarioExecutionReports.length;
const docRecap = duration.transform(Number.parseInt(report.duration)) + ' - ' + passedScenarioExecutionCount + ' OK / ' + totalscenarioExecutionCount;
pdf.setFontSize(pdfFontSize - 4);
pdf.text(docRecap, 148, 30, { align: 'center' });

const dataHeader = [["id", "Scenario", "Status", "error"]];
const dataBody = report.scenarioExecutionReports.map(s => [s.scenarioId.toString(), s.testCaseTitle, s.status, s.error.toString()]);
pdf.setFontSize(pdfFontSize - 2);
autoTable(pdf, {
body: dataBody,
head: dataHeader,
startY: 40,
theme: 'striped',
useCss: true,
didParseCell(data) {
CampaignReportService.setStatusStyle(data);
},
didDrawCell(data) {
if (data.cell.section === 'body' && data.column.index === 1) {
const scenarioId = data.row.cells[0].raw.toString();
const executionId = report.scenarioExecutionReports.filter(s => s.scenarioId === scenarioId).map(s => s.executionId).shift().toString();
pdf.link(data.cell.x, data.cell.y, data.cell.width, data.cell.height, { url: url.replace(':id', scenarioId).replace(new RegExp(':executionId', 'g'), executionId) });
}
}
});
}

private scenariiSummaryGeneration(pdf: jsPDF, report: CampaignExecutionFullReport) {
const scenariiDetailsTitle = this.translate.instant('campaigns.execution.scenarios.title');
pdf.text(scenariiDetailsTitle, 148, 15, { align: "center" });

const scenarioReportHeader = [["step", "Status", "error"]];

report.scenarioExecutionReports
.map(s => this.buildExecutionReport(s))
.forEach(r => {
pdf.text(r.scenarioName, 15, 25);
const scenarioReportBody = r.report.steps.map(step => [step.name, step.status, this.buildErrorMessage(step)]);
autoTable(pdf, {
body: scenarioReportBody,
head: scenarioReportHeader,
startY: 30,
theme: 'striped',
useCss: true,
didParseCell(data) {
CampaignReportService.setStatusStyle(data);
}
});
pdf.addPage();
});

pdf.deletePage(pdf.internal.pages.length - 1);
}

private buildErrorMessage(step: StepExecutionReport): string {
if (step.status === ExecutionStatus.FAILURE) {
const s = this.getFailedStep(step);
return '[ ' + s.name + ' ] ' + s.errors.toString();
}
return '';
}

private getFailedStep(step: StepExecutionReport): StepExecutionReport {
return (step.steps && step.steps.length) ? this.getFailedStep(step.steps.filter(s => s.status === ExecutionStatus.FAILURE)[0]) : step;
}

private buildExecutionReport(jsonResponse: any): ScenarioExecutionReport {
let report: StepExecutionReport;
let contextVariables: Map<string, Object>;
if (jsonResponse?.report) {
report = JSON.parse(jsonResponse.report).report;
contextVariables = JSON.parse(jsonResponse.report).contextVariables;
}
return new ScenarioExecutionReport(
jsonResponse.executionId,
jsonResponse.status ? jsonResponse.status : report?.status,
jsonResponse.duration ? jsonResponse.duration : report?.duration,
new Date(jsonResponse.time ? jsonResponse.time : report?.startDate),
report,
jsonResponse.environment,
jsonResponse.user,
jsonResponse.testCaseTitle,
jsonResponse.error,
contextVariables
);
}

private static setStatusStyle(data: CellHookData) {
if (data.cell.section === 'body') {
if (data.cell.raw === "FAILURE") {
data.cell.styles.textColor = [255, 255, 255];
data.cell.styles.fillColor = '#e74c3c';
}
if (data.cell.raw === "SUCCESS") {
data.cell.styles.textColor = [255, 255, 255];
data.cell.styles.fillColor = '#18bc9c';
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
<div *ngIf="errors.length > 0" class="alert alert-dismissible alert-danger mt-4">
<button type="button" class="btn-close" data-bs-dismiss="alert" (click)="errors = []"></button>
<ng-container *ngFor="let err of errors">
{{ err }}<br />
</ng-container>
</div>
<div *ngIf="report">

<div class="row">
Expand Down
Loading

0 comments on commit 413eb27

Please sign in to comment.