Skip to content

Commit

Permalink
ci: add job to send test results to gcp (#10379)
Browse files Browse the repository at this point in the history
closes: #XXXX
refs: #XXXX



## Description

This PR sends the results of all unit tests that run in github CI to GCP as metrics, which can be used to create alerts for failing or flaking tests

Metrics in GCP (link cannot be generated so here is a screenshot instead)
![image](https://github.com/user-attachments/assets/8aabde1f-6ac8-4984-9ff5-5a0b6cd65dc4)

### Security Considerations


### Scaling Considerations


### Documentation Considerations


### Testing Considerations


### Upgrade Considerations
  • Loading branch information
mergify[bot] authored Nov 4, 2024
2 parents 604ac38 + 6ac15c4 commit 1385184
Show file tree
Hide file tree
Showing 6 changed files with 409 additions and 6 deletions.
65 changes: 65 additions & 0 deletions .github/actions/ci-test-result.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#! /usr/bin/env node
const fs = require('node:fs');
const process = require('node:process');
const { sendMetricsToGCP, makeTimeSeries } = require('./gcp-monitoring.cjs');

const resultFiles = process.argv.slice(2);

const tapResultRegex = new RegExp(
`(^(?<status>not )?ok (?<num>[0-9]+) - (?<name>.+?)(?: %ava-dur=(?<duration>[0-9]+)ms)?(?:# (?<comments>.+?))?$(?<output>(\n^#.+?$)*)(?<failure>(\n^(?:(?!(?:not|ok) ))[^\n\r]+?$)*))`,
'gms',
);
let timeSeriesData = [];

function processTAP(packageName, tapbody) {
let m;
const returnValue = [];
// eslint-disable-next-line no-cond-assign
while ((m = tapResultRegex.exec(tapbody))) {
if (m.groups.name) {
const testCaseName = `${m.groups.name}`.replace(/["<>]/g, '').trim();

let skipped = false;
let succeeded = true;
let todo = false;
if (m.groups.status) {
succeeded = false;
}
if (m.groups.comments) {
if (m.groups.comments.match(/SKIP/gi)) {
skipped = true;
}
if (m.groups.comments.match(/TODO/gi)) {
todo = true;
skipped = true;
succeeded = true;
}
}
returnValue.push({
labels: {
test_name: testCaseName,
package: packageName,
test_status:
succeeded && !(todo || skipped)
? 'succeeded'
: !succeeded
? 'failed'
: 'skipped',
},
value: Number(succeeded && !(todo || skipped)),
});
}
}
return returnValue;
}

for (const file of resultFiles) {
const resultsBody = fs.readFileSync(file, 'utf-8');
const packageName = file.split('/').at(-2);

const response = processTAP(packageName, resultsBody);
timeSeriesData.push(...response);
}

const timeSeries = makeTimeSeries(timeSeriesData);
sendMetricsToGCP(timeSeries);
62 changes: 62 additions & 0 deletions .github/actions/gcp-monitoring.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
const Monitoring = require('@google-cloud/monitoring');

const gcpCredentials = JSON.parse(process.env.GCP_CREDENTIALS);
const projectId = gcpCredentials.project_id;

const monitoring = new Monitoring.MetricServiceClient({
projectId: gcpCredentials.project_id,
credentials: {
client_email: gcpCredentials.client_email,
private_key: gcpCredentials.private_key,
},
});

async function sendMetricsToGCP(timeSeries) {
const batchSize = 200;
for (let i = 0; i < timeSeries.length; i += batchSize) {
const batch = timeSeries.slice(i, i + batchSize);
const request = {
name: monitoring.projectPath(projectId),
timeSeries: batch,
};

try {
await monitoring.createTimeSeries(request);
console.log(
`Batch starting with metric ${batch[0].metric.type} sent successfully.`,
);
} catch (error) {
console.error('Error sending batch:', error);
}
}
}

function makeTimeSeries(testData) {
const timeSeries = testData.map(({ labels, value }) => ({
metric: {
type: `custom.googleapis.com/github/test-results`,
labels,
},
resource: {
type: 'global',
labels: {
project_id: projectId,
},
},
points: [
{
interval: {
endTime: {
seconds: Math.floor(Date.now() / 1000),
},
},
value: {
doubleValue: value,
},
},
],
}));
return timeSeries;
}

module.exports = { sendMetricsToGCP, makeTimeSeries };
11 changes: 11 additions & 0 deletions .github/actions/post-test/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ inputs:
description: 'site for datadog'
required: false
default: 'us3.datadoghq.com'
gcp-credentials:
description: 'gcp'
required: false
default: ''

runs:
using: composite
Expand Down Expand Up @@ -53,3 +57,10 @@ runs:
continue-on-error: true
with:
token: ${{ inputs.codecov-token }}
- name: Send test results to GCP
shell: bash
if: ${{ inputs.gcp-credentials }}
env:
GCP_CREDENTIALS: ${{ inputs.gcp-credentials }}
run: |
node .github/actions/ci-test-result.cjs ./packages/*/_testoutput.txt
10 changes: 10 additions & 0 deletions .github/workflows/test-all-packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ jobs:
with:
datadog-token: ${{ secrets.DATADOG_API_KEY }}
codecov-token: ${{ secrets.CODECOV_TOKEN }}
gcp-credentials: ${{ secrets.GCP_CREDENTIALS }}

test-quick2:
# BEGIN-TEST-BOILERPLATE
Expand Down Expand Up @@ -343,6 +344,7 @@ jobs:
with:
datadog-token: ${{ secrets.DATADOG_API_KEY }}
codecov-token: ${{ secrets.CODECOV_TOKEN }}
gcp-credentials: ${{ secrets.GCP_CREDENTIALS }}

##############
# Long-running tests are executed individually.
Expand Down Expand Up @@ -386,6 +388,7 @@ jobs:
with:
datadog-token: ${{ secrets.DATADOG_API_KEY }}
codecov-token: ${{ secrets.CODECOV_TOKEN }}
gcp-credentials: ${{ secrets.GCP_CREDENTIALS }}

test-solo:
# BEGIN-TEST-BOILERPLATE
Expand Down Expand Up @@ -427,6 +430,7 @@ jobs:
with:
datadog-token: ${{ secrets.DATADOG_API_KEY }}
codecov-token: ${{ secrets.CODECOV_TOKEN }}
gcp-credentials: ${{ secrets.GCP_CREDENTIALS }}

test-cosmic-swingset:
# BEGIN-TEST-BOILERPLATE
Expand Down Expand Up @@ -471,6 +475,7 @@ jobs:
with:
datadog-token: ${{ secrets.DATADOG_API_KEY }}
codecov-token: ${{ secrets.CODECOV_TOKEN }}
gcp-credentials: ${{ secrets.GCP_CREDENTIALS }}

test-inter-protocol:
# BEGIN-TEST-BOILERPLATE
Expand Down Expand Up @@ -512,6 +517,7 @@ jobs:
with:
datadog-token: ${{ secrets.DATADOG_API_KEY }}
codecov-token: ${{ secrets.CODECOV_TOKEN }}
gcp-credentials: ${{ secrets.GCP_CREDENTIALS }}

test-boot:
# BEGIN-TEST-BOILERPLATE
Expand Down Expand Up @@ -557,6 +563,7 @@ jobs:
with:
datadog-token: ${{ secrets.DATADOG_API_KEY }}
codecov-token: ${{ secrets.CODECOV_TOKEN }}
gcp-credentials: ${{ secrets.GCP_CREDENTIALS }}

test-swingset:
# BEGIN-TEST-BOILERPLATE
Expand Down Expand Up @@ -608,6 +615,7 @@ jobs:
with:
datadog-token: ${{ secrets.DATADOG_API_KEY }}
codecov-token: ${{ secrets.CODECOV_TOKEN }}
gcp-credentials: ${{ secrets.GCP_CREDENTIALS }}

test-zoe-unit:
# BEGIN-TEST-BOILERPLATE
Expand Down Expand Up @@ -651,6 +659,7 @@ jobs:
with:
datadog-token: ${{ secrets.DATADOG_API_KEY }}
codecov-token: ${{ secrets.CODECOV_TOKEN }}
gcp-credentials: ${{ secrets.GCP_CREDENTIALS }}

test-zoe-swingset:
# BEGIN-TEST-BOILERPLATE
Expand Down Expand Up @@ -693,3 +702,4 @@ jobs:
with:
datadog-token: ${{ secrets.DATADOG_API_KEY }}
codecov-token: ${{ secrets.CODECOV_TOKEN }}
gcp-credentials: ${{ secrets.GCP_CREDENTIALS }}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"packageManager": "[email protected]",
"devDependencies": {
"@endo/eslint-plugin": "^2.2.2",
"@google-cloud/monitoring": "^4.1.0",
"@jessie.js/eslint-plugin": "^0.4.1",
"@types/express": "^4.17.17",
"@types/node": "^22.0.0",
Expand Down
Loading

0 comments on commit 1385184

Please sign in to comment.