Skip to content

Commit

Permalink
test: add tests for Node.js APIs (#410)
Browse files Browse the repository at this point in the history
  • Loading branch information
jcbsfilho authored Oct 30, 2024
2 parents efefbbd + f9101a9 commit 3600ce5
Show file tree
Hide file tree
Showing 30 changed files with 848 additions and 31 deletions.
39 changes: 39 additions & 0 deletions .github/workflows/test-nodejs-apis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Test Node.js APIs

on:
schedule:
# Run every day at 3:30 AM UTC
- cron: '30 3 * * *'

jobs:
test-nodejs-apis:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/stage'
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.CUSTOM_GITHUB_TOKEN }}

- name: Install dependencies
run: yarn install

- name: Install Docker Compose
run: |
curl -L "https://github.com/docker/compose/releases/download/v2.29.7/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
docker-compose --version
- name: Run E2E tests
run: yarn test:nodejs-apis

- name: Process README.md and Commit
run: |
git config --global user.email "bundler@azion.com"
git config --global user.name "Azion Bundler Reports"
git add ./docs/nodejs-apis.md
git commit -m "chore: update reports node.js apis" --no-verify || echo "No changes to commit."
git push --force
env:
GH_TOKEN: ${{ secrets.CUSTOM_GITHUB_TOKEN }}
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "examples"]
path = examples
url = https://github.com/aziontech/vulcan-examples
url = https://github.com/aziontech/bundler-examples
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ RUN apk add ruby-dev

RUN gem install jekyll bundler

COPY . /vulcan
COPY . /bundler
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ One of the key highlights of Azion Bundler is its ability to establish an intuit

## Supported

E2E tests run daily in the [Vulcan Examples](https://github.com/aziontech/vulcan-examples/tree/main/examples) to ensure that the presets and frameworks continue to work correctly.
E2E tests run daily in the [Bundler Examples](https://github.com/aziontech/bundler-examples/tree/main/examples) to ensure that the presets and frameworks continue to work correctly.

Table:
| Test | Status |
Expand Down Expand Up @@ -227,6 +227,12 @@ To use wasm presets you need to install the necessary tools to build your code:
- Emscripten: [emsdk](https://emscripten.org/docs/getting_started/downloads.html);
- Rust/Wasm: [wasm-bindgen-cli](https://crates.io/crates/wasm-bindgen-cli)

## Node.js Support and Report

The compatibility between Azion Runtime and Node.js is an ongoing task, but a set of Node Runtime APIs are listed and compatible with Azion Runtime.

- [Node.js APIs support](docs/nodejs-apis.md)

## Contributing

Check the [Contributing doc](CONTRIBUTING.md).
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ services:
ports:
- "3000-3040:3000-3040"
volumes:
- ./:/vulcan/
- ./:/bundler/
working_dir: /
tty: true
58 changes: 58 additions & 0 deletions docs/nodejs-apis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
### Node.js APIs

Azion Bundler provides a set of APIs to help you build and test your Node.js projects. The following sections detail the available APIs and how to use them.

#### Example usage

See more: [Buffer Example](https://github.com/aziontech/bundler-examples/tree/main/examples/runtime-apis/nodejs/buffer)

```javascript
import { Buffer } from "node:buffer";

const main = async (event) => {
const helloBuffer = Buffer.from("Hello Edge!", "utf8");
console.log(helloBuffer.toString("hex"));
// 48656c6c6f204564676521
console.log(helloBuffer.toString("base64"));
// SGVsbG8gRWRnZSE=

helloBuffer.write("World", 6, 5, "utf8");
console.log(helloBuffer.toString());
// Hello World!
return new Response(helloBuffer.toString(), { status: 200 });
};

export default main;

```

#### Support report

Tests run daily in the [Bundler Examples](https://github.com/aziontech/bundler-examples/tree/main/examples/runtime-apis/nodejs).

Table:
| Test | Status |
| -------------- | ------ |
| Timers ||
| Http ||
| Async Hooks ||
| String Decoder ||
| Url ||
| Crypto ||
| Process ||
| Util ||
| Vm ||
| Zlib ||
| Os ||
| Buffer ||
| Module ||
| Stream ||
| Fs ||
| Events ||
| Path ||

Last test run date: 10/30/24 11:16:36 AM
#### Docs support

See support for the Node.js APIs in the [https://www.azion.com/en/documentation/products/azion-edge-runtime/compatibility/node/](https://www.azion.com/en/documentation/products/azion-edge-runtime/compatibility/node/)

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"start": "node lib/main.js",
"task:aliases": "node tasks/sync-aliases.js",
"task:reports": "node tasks/process-reports-e2e.js",
"task:reports-nodejs-apis": "node tasks/process-reports-nodejs-apis.js",
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"format": "prettier --write .",
Expand All @@ -25,6 +26,7 @@
"e2e:stop": "tests/scripts/stop-e2e-env.sh",
"e2e:destroy": "tests/scripts/destroy-e2e-env.sh",
"test:e2e": "yarn e2e:start && jest --maxWorkers 1 tests/e2e/ --json --outputFile e2e_results.json && yarn e2e:stop; yarn task:reports",
"test:nodejs-apis": "yarn e2e:start && jest --maxWorkers 1 tests/nodejs-apis/ --json --outputFile nodejs_apis_results.json && yarn e2e:stop && yarn task:reports-nodejs-apis",
"prepare": "husky install",
"submodule:update": "git submodule update --init --recursive && git submodule foreach git pull origin main"
},
Expand Down
100 changes: 100 additions & 0 deletions tasks/process-reports-nodejs-apis.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import fs from 'fs';
import { feedback } from '#utils';
// eslint-disable-next-line import/no-extraneous-dependencies
import { markdownTable } from 'markdown-table';

/**
*
*/
function processReports() {
try {
feedback.interactive.await('Processing Node.js APIs report...');

// Read the JSON file
const data = fs.readFileSync('nodejs_apis_results.json');
const results = JSON.parse(data);

// Process the test results
results.testResults = results.testResults.map((test) => {
// Remove the path from the test name
const testName = test.name
.split('/')
.pop()
.replace('.test.js', '')
.replace(/-/g, ' ');

// Transform the test name into a more readable format
const readableTestName = testName
.split(' ')
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');

// Check if all tests in the suite passed
const suitePassed = test.assertionResults.every(
(result) => result.status === 'passed',
);

return {
name: readableTestName,
passed: suitePassed,
};
});

// Update the overall test status
results.passes = results.testResults.every((test) => test.passed);

// Create a new object with the testResults and passes properties
const newResults = {
testResults: results.testResults,
passes: results.passes,
};

// Write the new object back to the JSON file
fs.writeFileSync(
'nodejs_apis_results.json',
JSON.stringify(newResults, null, 2),
);

// Create the Markdown table
const table = [
['Test', 'Status'],
...newResults.testResults.map((test) => [
test.name,
test.passed ? '✅' : '⚠️',
]),
];

// Write the Markdown table to the README.md file
const readme = fs.readFileSync('./docs/nodejs-apis.md', 'utf8');
const newReadme = readme.replace(
/(Table:\n)(.*?)(\n#### Docs support)/s,
(match, p1, p2, p3) => {
const dateOptions = {
day: '2-digit',
month: '2-digit',
year: '2-digit',
};
const timeOptions = {
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
};
const newDate = `${new Date().toLocaleDateString(
'en-US',
dateOptions,
)} ${new Date().toLocaleTimeString('en-US', timeOptions)}`;
return `${p1}${markdownTable(
table,
)}\n\nLast test run date: ${newDate}${p3}`;
},
);
fs.writeFileSync('./docs/nodejs-apis.md', newReadme);

feedback.interactive.success('Report processed successfully.');
} catch (error) {
console.error('An error occurred:', error);
}
}

// Call the function
processReports();
33 changes: 33 additions & 0 deletions tests/nodejs-apis/async-hooks.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import supertest from 'supertest';
import projectInitializer from '../utils/project-initializer.js';
import projectStop from '../utils/project-stop.js';
import { getContainerPort } from '../utils/docker-env-actions.js';

// timeout in minutes
const TIMEOUT = 1 * 60 * 3000;

let serverPort;
let localhostBaseUrl;
const EXAMPLE_PATH = '/examples/runtime-apis/nodejs/async-hooks';

describe('Node.js APIs - async_hooks', () => {
let request;

beforeAll(async () => {
serverPort = getContainerPort();
localhostBaseUrl = `http://0.0.0.0:${serverPort}`;

request = supertest(localhostBaseUrl);

await projectInitializer(EXAMPLE_PATH, 'javascript', serverPort, false);
}, TIMEOUT);

afterAll(async () => {
await projectStop(serverPort, EXAMPLE_PATH.replace('/examples/', ''));
}, TIMEOUT);

test('should request the "/" route and get a 200 status code', async () => {
const response = await request.get('/').expect(200);
expect(response.text).toContain('ok');
});
});
34 changes: 34 additions & 0 deletions tests/nodejs-apis/buffer.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import supertest from 'supertest';
import { expect } from '@jest/globals';
import projectInitializer from '../utils/project-initializer.js';
import projectStop from '../utils/project-stop.js';
import { getContainerPort } from '../utils/docker-env-actions.js';

// timeout in minutes
const TIMEOUT = 1 * 60 * 3000;

let serverPort;
let localhostBaseUrl;
const EXAMPLE_PATH = '/examples/runtime-apis/nodejs/buffer';

describe('Node.js APIs - buffer', () => {
let request;

beforeAll(async () => {
serverPort = getContainerPort();
localhostBaseUrl = `http://0.0.0.0:${serverPort}`;

request = supertest(localhostBaseUrl);

await projectInitializer(EXAMPLE_PATH, 'javascript', serverPort, false);
}, TIMEOUT);

afterAll(async () => {
await projectStop(serverPort, EXAMPLE_PATH.replace('/examples/', ''));
}, TIMEOUT);

test('should request the "/" route and get a 200 status code', async () => {
const response = await request.get('/').expect(200);
expect(response.text).toContain('Hello World');
});
});
36 changes: 36 additions & 0 deletions tests/nodejs-apis/crypto.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import supertest from 'supertest';
import { expect } from '@jest/globals';
import projectInitializer from '../utils/project-initializer.js';
import projectStop from '../utils/project-stop.js';
import { getContainerPort } from '../utils/docker-env-actions.js';

// timeout in minutes
const TIMEOUT = 1 * 60 * 3000;

let serverPort;
let localhostBaseUrl;
const EXAMPLE_PATH = '/examples/runtime-apis/nodejs/crypto';

describe('Node.js APIs - crypto', () => {
let request;
const uuidRegex =
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;

beforeAll(async () => {
serverPort = getContainerPort();
localhostBaseUrl = `http://0.0.0.0:${serverPort}`;

request = supertest(localhostBaseUrl);

await projectInitializer(EXAMPLE_PATH, 'javascript', serverPort, false);
}, TIMEOUT);

afterAll(async () => {
await projectStop(serverPort, EXAMPLE_PATH.replace('/examples/', ''));
}, TIMEOUT);

test('should request the "/" route and get a 200 status code', async () => {
const response = await request.get('/').expect(200);
expect(response.text).toMatch(uuidRegex);
});
});
Loading

0 comments on commit 3600ce5

Please sign in to comment.