Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

upload attachments #184

Merged
merged 1 commit into from
Jun 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 30 additions & 33 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "testbeats",
"version": "2.0.2",
"version": "2.0.3",
"description": "Publish test results to Microsoft Teams, Google Chat, Slack and InfluxDB",
"main": "src/index.js",
"types": "./src/index.d.ts",
Expand Down Expand Up @@ -48,6 +48,7 @@
"dependencies": {
"async-retry": "^1.3.3",
"dotenv": "^14.3.2",
"form-data-lite": "^1.0.3",
"influxdb-lite": "^1.0.0",
"performance-results-parser": "latest",
"phin-retry": "^1.0.3",
Expand Down
11 changes: 11 additions & 0 deletions src/beats/beats.api.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ class BeatsApi {
});
}

uploadAttachments(headers, payload) {
return request.post({
url: `${this.getBaseUrl()}/api/core/v1/test-cases/attachments`,
headers: {
'x-api-key': this.config.api_key,
...headers
},
body: payload
});
}

getBaseUrl() {
return process.env.TEST_BEATS_URL || "https://app.testbeats.com";
}
Expand Down
100 changes: 100 additions & 0 deletions src/beats/beats.attachments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
const fs = require('fs');
const path = require('path');
const FormData = require('form-data-lite');
const TestResult = require('test-results-parser/src/models/TestResult');
const { BeatsApi } = require('./beats.api');
const logger = require('../utils/logger');

const MAX_ATTACHMENTS_PER_REQUEST = 5;
const MAX_ATTACHMENTS_PER_RUN = 20;
const MAX_ATTACHMENT_SIZE = 1024 * 1024;

class BeatsAttachments {

/**
* @param {import('../index').PublishReport} config
* @param {TestResult} result
*/
constructor(config, result, test_run_id) {
this.config = config;
this.result = result;
this.api = new BeatsApi(config);
this.test_run_id = test_run_id;
this.failed_test_cases = [];
this.attachments = [];
}

async upload() {
this.#setAllFailedTestCases();
this.#setAttachments();
await this.#uploadAttachments();
}

#setAllFailedTestCases() {
for (const suite of this.result.suites) {
for (const test of suite.cases) {
if (test.status === 'FAIL') {
this.failed_test_cases.push(test);
}
}
}
}

#setAttachments() {
for (const test_case of this.failed_test_cases) {
for (const attachment of test_case.attachments) {
this.attachments.push(attachment);
}
}
}

async #uploadAttachments() {
if (this.attachments.length === 0) {
return;
}
logger.info(`⏳ Uploading ${this.attachments.length} attachments...`);
const result_file = this.config.results[0].files[0];
const result_file_dir = path.dirname(result_file);
try {
let count = 0;
const size = MAX_ATTACHMENTS_PER_REQUEST;
for (let i = 0; i < this.attachments.length; i += size) {
if (count >= MAX_ATTACHMENTS_PER_RUN) {
logger.warn('⚠️ Maximum number of attachments per run reached. Skipping remaining attachments.');
break;
}
const attachments_subset = this.attachments.slice(i, i + size);
const form = new FormData();
const file_images = []
for (const attachment of attachments_subset) {
const attachment_path = path.join(result_file_dir, attachment.path);
const stats = fs.statSync(attachment_path);
if (stats.size > MAX_ATTACHMENT_SIZE) {
logger.warn(`⚠️ Attachment ${attachment.path} is too big (${stats.size} bytes). Allowed size is ${MAX_ATTACHMENT_SIZE} bytes.`);
continue;
}
form.append('images', fs.readFileSync(attachment_path));
form.append('test_run_id', this.test_run_id);
file_images.push({
file_name: attachment.name,
file_path: attachment.path,
});
count += 1;
}
if (file_images.length === 0) {
return;
}
form.append('file_images', JSON.stringify(file_images));
await this.api.uploadAttachments(form.getHeaders(), form.getBuffer());
logger.info(`🏞️ Uploaded ${count} attachments`);
}
} catch (error) {
logger.error(`❌ Unable to upload attachments: ${error.message}`, error);
}
}



}

module.exports = { BeatsAttachments }
30 changes: 30 additions & 0 deletions src/beats/beats.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ const { getCIInformation } = require('../helpers/ci');
const logger = require('../utils/logger');
const { BeatsApi } = require('./beats.api');
const { HOOK } = require('../helpers/constants');
const TestResult = require('test-results-parser/src/models/TestResult');
const { BeatsAttachments } = require('./beats.attachments');

class Beats {

Expand All @@ -22,6 +24,7 @@ class Beats {
this.#setRunName();
this.#setApiKey();
await this.#publishTestResults();
await this.#uploadAttachments();
this.#updateTitleLink();
await this.#attachFailureSummary();
}
Expand Down Expand Up @@ -69,6 +72,33 @@ class Beats {
return payload;
}

async #uploadAttachments() {
if (!this.test_run_id) {
return;
}
if (this.result.status !== 'FAIL') {
return;
}
try {
const attachments = new BeatsAttachments(this.config, this.result, this.test_run_id);
await attachments.upload();
} catch (error) {
logger.error(`❌ Unable to upload attachments: ${error.message}`, error);
}
}

#getAllFailedTestCases() {
const test_cases = [];
for (const suite of this.result.suites) {
for (const test of suite.cases) {
if (test.status === 'FAIL') {
test_cases.push(test);
}
}
}
return test_cases;
}

#updateTitleLink() {
if (!this.test_run_id) {
return;
Expand Down
Loading
Loading