Skip to content

Commit

Permalink
feat(regression-tests): adding manually dispatched GHA for US end-to-…
Browse files Browse the repository at this point in the history
…end testing
  • Loading branch information
mbruzina committed Mar 26, 2024
1 parent 6bb1668 commit 506b5eb
Show file tree
Hide file tree
Showing 3 changed files with 356 additions and 0 deletions.
115 changes: 115 additions & 0 deletions .github/scripts/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
const https = require('https')
const {SQSClient, SendMessageCommand} = require('@aws-sdk/client-sqs')
const {DynamoDBClient, QueryCommand} = require('@aws-sdk/client-dynamodb')
const {unmarshall} = require('@aws-sdk/util-dynamodb')

const AWS_REGION = process.env.AWS_REGION
const SQS_URL = process.env.SQS_URL
const DYNAMO_TABLE = process.env.DYNAMO_TABLE
const AWS_CREDS = {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
};

const sqs = new SQSClient({region: AWS_REGION, credentials: AWS_CREDS})
const dynamodb = new DynamoDBClient({region: AWS_REGION, credentials: AWS_CREDS})


function queryForDeploymentStatus(messageId) {
const query_params = {
TableName: DYNAMO_TABLE,
KeyConditionExpression: 'id = :id',
FilterExpression: 'completed = :completed',
ExpressionAttributeNames: {
'#id': 'id',
'#completed': 'completed',
'#status': 'status',
'#message': 'message',
},
ExpressionAttributeValues: {
':id': {
S: messageId,
},
':completed': {
BOOL: true,
},
},
ProjectionExpression: '#id, #completed, #status, #message',
ScanIndexForward: false, //returns items by descending timestamp
}
return new QueryCommand(query_params)
}

async function isDeploymentSuccessful(deploymentId, retries, waitSeconds) {
for (let i = 0; i < retries; i++) {
console.log(`Deployment pending, sleeping ${waitSeconds} seconds...`)
await sleep(waitSeconds * 1000)

try {
const response = await dynamodb.send(queryForDeploymentStatus(deploymentId))
console.log(`Query succeeded. Items found: ${response.Items.length}`)

for (let i = 0; i < response.Items.length; i++) {
const item = unmarshall(response.Items[i])
if (item.completed) {
console.log(`Completed: ${item.id} - ${item.message} - ${item.completed} - ${item.status}`)
if (item.status === 'FAILED') {
console.error(`::error:: Deployment failed: ${item.message}`)
return false
}

return true
}
}
} catch (err) {
console.log(`Error querying table: ${err}`)
}
}
return false
}

function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms))
}

function main() {
const url = process.env.TEST_DEFINITION_URL

https.get(url, (res) => {
let body = ''

res.on('data', (chunk) => {
body += chunk
})

res.on('end', async () => {
let messageId
try {
const command = new SendMessageCommand({
QueueUrl: SQS_URL,
MessageBody: body,
})
data = await sqs.send(command)
messageId = data.MessageId
console.log(`Message sent: ${messageId}`)
} catch (err) {
console.error(`Error sending message: ${err}`)
}

// Execute the query with retries/sleeps
let RETRIES = 200, WAIT_SECONDS = 15
const success = await isDeploymentSuccessful(messageId, RETRIES, WAIT_SECONDS)
if (!success) {
process.exit(1)
}
})

res.on('error', (err) => {
console.error(`Error calling URL: ${err}`)
})
})
}

if (require.main === module) {
main()
}
19 changes: 19 additions & 0 deletions .github/scripts/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "scripts",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"@actions/core": "1.2.6",
"@aws-sdk/client-sqs": "3.27.0",
"@aws-sdk/client-dynamodb": "3.27.0",
"@aws-sdk/util-dynamodb": "3.27.0",
"@aws-sdk/credential-providers": "3.451.0"
},
"keywords": [],
"author": "",
"license": "ISC"
}
222 changes: 222 additions & 0 deletions .github/workflows/e2e-dp-us.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
name: End to end testing

on:
workflow_dispatch:
# push:
# branches: [main]
# pull_request:
# branches: [main]
# workflow_run:
# workflows: ["Release"]
# types: [requested]

jobs:
get-test-definition-files:
name: Get Test Definition Files
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.get-test-definition-files.outputs.result }}
steps:
- name: Checkout Repo
uses: actions/checkout@v3
with:
repository: newrelic/open-install-library
path: open-install-library

- name: Get Test Definition Files
id: get-test-definition-files
uses: actions/github-script@v3
with:
script: |
const fs = require("fs");
const fsp = fs.promises;
const path = require("path");
// readdir recursive directory search
const { readdir } = fsp;
async function getFiles(dir) {
const dirents = await readdir(dir, { withFileTypes: true });
const files = await Promise.all(
dirents.map((dirent) => {
const res = path.join(dir, dirent.name);
return dirent.isDirectory() ? getFiles(res) : res;
})
);
return Array.prototype.concat(...files);
}
const testDefinitions = await getFiles(`${process.env.GITHUB_WORKSPACE}/open-install-library/test/definitions/smoke`);
const outputTestFilesMap = testDefinitions
.map((testDefinitionFile) => {
return {
testDefinitionFile,
testDisplayName: testDefinitionFile.split("/").pop(),
testDefinitionSuffix: `/test/definitions/smoke/${testDefinitionFile.split("/").pop()}`
};
});
const output = {
include: outputTestFilesMap,
};
console.log(output);
return output;
validate:
name: ${{ matrix.testDisplayName }}
needs: [get-test-definition-files]
if: ${{ fromJSON(needs.get-test-definition-files.outputs.matrix).include[0] }} # Avoids empty matrix validation error
runs-on: ubuntu-latest
strategy:
matrix: ${{ fromJSON(needs.get-test-definition-files.outputs.matrix) }}
fail-fast: false
env:
MATRIX: ${{ toJSON(matrix) }}
steps:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: 1.19.x

- name: Add GOBIN to PATH
run: echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
shell: bash

- name: Checkout Repo
uses: actions/checkout@v3

- name: Checkout Repo
uses: actions/checkout@v3
with:
repository: newrelic/open-install-library
path: open-install-library

- name: Install Snapcraft
uses: samuelmeuli/action-snapcraft@v2
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_TOKEN }}

- name: Install PGP private key
shell: bash
env:
PGP_PRIVATE_KEY: ${{ secrets.PGP_PRIVATE_KEY }}
run: echo "$PGP_PRIVATE_KEY" | gpg --batch --import

- name: Compile all distros
continue-on-error: true
env:
SPLIT_PROD_KEY: ${{ secrets.SPLIT_PROD_KEY }}
SPLIT_STAGING_KEY: ${{ secrets.SPLIT_STAGING_KEY }}
SEGMENT_WRITE_KEY: ${{ secrets.SEGMENT_WRITE_KEY }}
# Creating the Snapcraft directories ahead of the snapshot is a workaround
# to deal with a race condition with parallel builds between distros.
#
# https://github.com/goreleaser/goreleaser/issues/1715#issuecomment-667002748
run: |
mkdir -p $HOME/.cache/snapcraft/download
mkdir -p $HOME/.cache/snapcraft/stage-packages
make snapshot
# Inject newrelic cli path to any of the smoke tests
- name: Add newrelic cli path to smoke tests
id: add-newrelic-cli-path-smoke-tests
uses: actions/github-script@v6
continue-on-error: false
env:
TEST_DEFINITION_FILE: ${{ matrix.testDefinitionFile }}
with:
script: |
const fs = require('fs');
const fsp = fs.promises;
const path = require('path');
// readdir recursive directory search
const { resolve } = path;
const { readdir } = fsp;
const newrelic_cli_linux_amd64_source_path = `${process.env.GITHUB_WORKSPACE}/dist/newrelic_linux_amd64_v1/newrelic`;
const newrelic_cli_linux_amd64_docker_path = `/mnt/deployer/dist/newrelic_linux_amd64_v1/newrelic`;
console.log(`Using cli linux source path ${newrelic_cli_linux_amd64_source_path}`);
if (!fs.existsSync(newrelic_cli_linux_amd64_source_path)) {
throw new Error(`The newrelic cli amd64 source does NOT exist ${newrelic_cli_linux_amd64_source_path}`);
}
const newrelic_cli_linux_arm64_source_path = `${process.env.GITHUB_WORKSPACE}/dist/newrelic_linux_arm64/newrelic`;
const newrelic_cli_linux_arm64_docker_path = `/mnt/deployer/dist/newrelic_linux_arm64/newrelic`;
console.log(`Using cli linux source path ${newrelic_cli_linux_arm64_source_path}`);
if (!fs.existsSync(newrelic_cli_linux_arm64_source_path)) {
throw new Error(`The newrelic cli arm64 source does NOT exist ${newrelic_cli_linux_arm64_source_path}`);
}
const newrelic_cli_windows_source_path = `${process.env.GITHUB_WORKSPACE}/dist/newrelic_windows_amd64_v1/newrelic.exe`;
const newrelic_cli_windows_docker_path = `/mnt/deployer/dist/newrelic_windows_amd64_v1/newrelic.exe`;
console.log(`Using cli windows source path ${newrelic_cli_windows_source_path}`);
if (!fs.existsSync(newrelic_cli_windows_source_path)) {
throw new Error(`The newrelic cli windows source does NOT exist ${newrelic_cli_windows_source_path}`);
}
// Get testDefinitionFile from MATRIX env var
const testDefinitionFile = process.env.TEST_DEFINITION_FILE;
console.log(`Detected Deploy Config: ${JSON.stringify(testDefinitionFile, null, 2)}`)
const jsonData = require(testDefinitionFile);
var isUpdated = false
var isWindows = false
var isArm64 = false
if (jsonData.resources) {
jsonData.resources.forEach(resource => {
if (resource.is_windows) {
isWindows = true;
}
if (!!resource.ami_name && resource.ami_name.toLowerCase().includes("arm64")) {
isArm64 = true;
}
});
}
if (jsonData.instrumentations) {
if (jsonData.instrumentations.resources) {
jsonData.instrumentations.resources.forEach(resource => {
if (resource.params) {
isUpdated = true;
resource.params.newrelic_cli_path = `${newrelic_cli_linux_amd64_docker_path}`;
if (isWindows) {
resource.params.newrelic_cli_path = `${newrelic_cli_windows_docker_path}`;
}
else if (isArm64) {
resource.params.newrelic_cli_path = `${newrelic_cli_linux_arm64_docker_path}`;
}
}
});
}
}
if (isUpdated) {
// Write file back to workspace
let jsonContent = JSON.stringify(jsonData, null, 2);
console.log("Updated Deploy Config File: ", testDefinitionFile);
console.log("Deploy Config content: ", jsonContent);
const outputPath = `${testDefinitionFile}`;
fs.writeFileSync(outputPath, jsonContent);
}
return testDefinitionFile;
- name: Install npm dependencies for deployer test runner
working-directory: ${{ github.workspace }}/.github/scripts
run: npm install

- name: Execute test
working-directory: ${{ github.workspace }}/.github/scripts
run: node main.js
env:
TEST_DEFINITION_URL: https://raw.githubusercontent.com/newrelic/open-install-library/main${{ matrix.testDefinitionSuffix }}
AWS_ACCESS_KEY_ID: ${{ secrets.DEPLOYER_PLATFORM_US_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.DEPLOYER_PLATFORM_US_AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ secrets.DEPLOYER_PLATFORM_US_AWS_REGION }}
SQS_URL: ${{ secrets.DEPLOYER_PLATFORM_US_SQS_URL }}
DYNAMO_TABLE: ${{ secrets.DEPLOYER_PLATFORM_US_DYNAMO_TABLE }}

- name: Report any error
if: steps.deployerRun.outputs.exit_status != 0
run: exit 1

0 comments on commit 506b5eb

Please sign in to comment.