mirror of
https://github.com/tlsnotary/tlsn-js.git
synced 2026-01-06 19:23:54 -05:00
chore: fix test in github action (#41)
* Typescript tests in chrome * increase timeout to 5min * close page * force close browser * force exit process * refactor: clean up test code * chore: update readme for adding a new test
This commit is contained in:
19
.github/workflows/test.yaml
vendored
19
.github/workflows/test.yaml
vendored
@@ -7,7 +7,8 @@ on:
|
||||
branches: [ main ]
|
||||
|
||||
env:
|
||||
LOCAL: true
|
||||
LOCAL-NOTARY: true
|
||||
LOCAL-WS: false
|
||||
HEADLESS: true
|
||||
PUPPETEER_SKIP_DOWNLOAD: true
|
||||
|
||||
@@ -31,6 +32,15 @@ jobs:
|
||||
with:
|
||||
workspaces: wasm/prover
|
||||
|
||||
- name: Install Chrome
|
||||
uses: browser-actions/setup-chrome@v1
|
||||
id: setup-chrome
|
||||
with:
|
||||
chrome-version: 121.0.6167.85
|
||||
|
||||
- name: Set CHROME_PATH environment variable
|
||||
run: echo "CHROME_PATH=${{ steps.setup-chrome.outputs['chrome-path'] }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
@@ -50,7 +60,7 @@ jobs:
|
||||
- uses: actions/cache@v4
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ env.STORE_PATH }}
|
||||
path: ${STORE_PATH}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
@@ -67,9 +77,8 @@ jobs:
|
||||
- name: Build WASM
|
||||
run: npm run build:wasm
|
||||
|
||||
- name: Test WASM
|
||||
run: npm run test:wasm
|
||||
- name: Build Test dependencies
|
||||
run: npm run build:tlsn-binaries
|
||||
|
||||
- name: Test
|
||||
if: false
|
||||
run: npm run test
|
||||
@@ -6,5 +6,5 @@
|
||||
"source-map-support/register"
|
||||
],
|
||||
"recursive": true,
|
||||
"timeout": 60000
|
||||
"timeout": 300000
|
||||
}
|
||||
10
package.json
10
package.json
@@ -20,6 +20,7 @@
|
||||
"update:wasm": "sh utils/check-wasm.sh -f",
|
||||
"test:wasm": "cd wasm/prover; wasm-pack test --firefox --release --headless",
|
||||
"build:wasm": "wasm-pack build --target web wasm/prover",
|
||||
"build:tlsn-binaries": "sh utils/build-tlsn-binaries.sh",
|
||||
"watch:dev": "webpack --config webpack.web.dev.config.js --watch",
|
||||
"predev": "sh utils/check-wasm.sh",
|
||||
"lint:wasm": "cd wasm/prover; cargo clippy --target wasm32-unknown-unknown",
|
||||
@@ -28,7 +29,7 @@
|
||||
"lint:tsc": "tsc --noEmit",
|
||||
"lint": "concurrently npm:lint:tsc npm:lint:eslint",
|
||||
"run:test": "TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\"}' mocha -r ts-node/register 'test/testRunner.ts'",
|
||||
"test": "npm run build:test && npm run run:test"
|
||||
"test": "npm run build:tlsn-binaries && npm run build:test && npm run run:test"
|
||||
},
|
||||
"dependencies": {
|
||||
"comlink": "^4.4.1"
|
||||
@@ -38,6 +39,7 @@
|
||||
"@types/mocha": "^10.0.6",
|
||||
"@types/serve-handler": "^6.1.4",
|
||||
"@typescript-eslint/eslint-plugin": "^6.15.0",
|
||||
"@typescript-eslint/parser": "7.0.2",
|
||||
"browserify": "^17.0.0",
|
||||
"concurrently": "^5.1.0",
|
||||
"constants-browserify": "^1.0.0",
|
||||
@@ -50,6 +52,7 @@
|
||||
"html-webpack-plugin": "~5.3.2",
|
||||
"https-browserify": "^1.0.0",
|
||||
"image-webpack-loader": "^6.0.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"mocha": "^10.2.0",
|
||||
"node-loader": "^0.6.0",
|
||||
"prettier": "^3.0.2",
|
||||
@@ -65,11 +68,12 @@
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^5.0.0",
|
||||
"webpack-dev-server": "^4.11.1",
|
||||
"webpack-node-externals": "^3.0.0"
|
||||
"webpack-node-externals": "^3.0.0",
|
||||
"wtfnode": "^0.9.1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">= 16.20.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,3 +63,10 @@ npm run dev
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
## Adding a new test
|
||||
1. Create a new `new-test.spec.ts` file in the `test/` directory
|
||||
2. Add your spec file to the entry object fin `webpack.web.dev.config.js`
|
||||
3. Add a new `div` block to `test/test.ejs` like this: `<div>Testing "new-test":<div id="new-test"></div></div>`. The div id must be the same as the filename.
|
||||
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import { verify } from '../src';
|
||||
import simple_proof_redacted from './assets/simple_proof_redacted.json';
|
||||
|
||||
(async function verify_simple() {
|
||||
try {
|
||||
const pem = `-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEBv36FI4ZFszJa0DQFJ3wWCXvVLFr\ncRzMG5kaTeHGoSzDu6cFqx3uEWYpFGo6C0EOUgf+mEgbktLrXocv5yHzKg==\n-----END PUBLIC KEY-----`;
|
||||
const proof = {
|
||||
...simple_proof_redacted,
|
||||
notaryUrl: 'http://localhost:7047',
|
||||
};
|
||||
console.log(proof);
|
||||
console.time('verify');
|
||||
const result = await verify(proof, pem);
|
||||
console.timeEnd('verify');
|
||||
|
||||
// @ts-ignore
|
||||
document.getElementById('simple-verify').textContent =
|
||||
JSON.stringify(result);
|
||||
} catch (err) {
|
||||
console.log('caught error from wasm');
|
||||
console.error(err);
|
||||
}
|
||||
})();
|
||||
@@ -1,4 +1,5 @@
|
||||
import { prove, verify } from '../src';
|
||||
import { prove, verify } from '../../src';
|
||||
import { assert } from '../utils';
|
||||
|
||||
(async function () {
|
||||
try {
|
||||
@@ -9,10 +10,10 @@ import { prove, verify } from '../src';
|
||||
method: 'GET',
|
||||
headers: { secret: 'test_secret' },
|
||||
maxTranscriptSize: 16384,
|
||||
notaryUrl: process.env.LOCAL
|
||||
notaryUrl: process.env.LOCAL_NOTARY
|
||||
? 'http://localhost:7047'
|
||||
: 'https://notary.pse.dev',
|
||||
websocketProxyUrl: process.env.LOCAL
|
||||
websocketProxyUrl: process.env.LOCAL_WS
|
||||
? 'ws://localhost:55688'
|
||||
: 'wss://notary.pse.dev/proxy?token=swapi.dev',
|
||||
secretHeaders: ['test_secret'],
|
||||
@@ -27,11 +28,20 @@ import { prove, verify } from '../src';
|
||||
console.timeEnd('verify');
|
||||
|
||||
console.log(result);
|
||||
|
||||
assert(result.sent.includes('host: swapi.dev'));
|
||||
assert(result.sent.includes('secret: XXXXXXXXXXX'));
|
||||
assert(result.recv.includes('Luke Skywalker'));
|
||||
assert(result.recv.includes('"hair_color":"XXXXX"'));
|
||||
assert(result.recv.includes('"skin_color":"XXXX"'));
|
||||
|
||||
// @ts-ignore
|
||||
document.getElementById('full-integration-swapi').textContent =
|
||||
JSON.stringify(result);
|
||||
document.getElementById('full-integration-swapi').textContent = 'OK';
|
||||
} catch (err) {
|
||||
console.log('caught error from wasm');
|
||||
console.error(err);
|
||||
|
||||
// @ts-ignore
|
||||
document.getElementById('full-integration-swapi').textContent = err.message;
|
||||
}
|
||||
})();
|
||||
34
test/specs/simple-verify.spec.ts
Normal file
34
test/specs/simple-verify.spec.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { verify } from '../../src';
|
||||
import simple_proof_redacted from '../assets/simple_proof_redacted.json';
|
||||
import { assert } from '../utils';
|
||||
|
||||
(async function verify_simple() {
|
||||
try {
|
||||
const pem = `-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEBv36FI4ZFszJa0DQFJ3wWCXvVLFr\ncRzMG5kaTeHGoSzDu6cFqx3uEWYpFGo6C0EOUgf+mEgbktLrXocv5yHzKg==\n-----END PUBLIC KEY-----`;
|
||||
const proof = {
|
||||
...simple_proof_redacted,
|
||||
notaryUrl: 'http://127.0.0.1:7047',
|
||||
};
|
||||
console.log(proof);
|
||||
console.time('verify');
|
||||
const result = await verify(proof, pem);
|
||||
console.timeEnd('verify');
|
||||
|
||||
assert(
|
||||
result.sent.includes(
|
||||
'user-agent: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
|
||||
),
|
||||
);
|
||||
assert(result.recv.includes('<h1>XXXXXXXXXXXXXX</h1>'));
|
||||
assert(result);
|
||||
|
||||
// @ts-ignore
|
||||
document.getElementById('simple-verify').textContent = 'OK';
|
||||
} catch (err) {
|
||||
console.log('caught error from wasm');
|
||||
console.error(err);
|
||||
|
||||
// @ts-ignore
|
||||
document.getElementById('simple-verify').textContent = err.message;
|
||||
}
|
||||
})();
|
||||
@@ -1,67 +1,167 @@
|
||||
import puppeteer from 'puppeteer';
|
||||
import puppeteer, { Browser, Page, PuppeteerLaunchOptions } from 'puppeteer';
|
||||
import { describe, it, before, after } from 'mocha';
|
||||
const assert = require('assert');
|
||||
const { exec } = require('node:child_process');
|
||||
import { exec, ChildProcess } from 'node:child_process';
|
||||
import * as fs from 'fs';
|
||||
import path from 'path';
|
||||
const yaml = require('js-yaml');
|
||||
|
||||
const timeout = 300000;
|
||||
|
||||
// puppeteer options
|
||||
const opts = {
|
||||
headless: !!process.env.HEADLESS,
|
||||
let opts: PuppeteerLaunchOptions = {
|
||||
headless: !!process.env.HEADLESS ? 'new' : false,
|
||||
slowMo: 100,
|
||||
timeout: 60000,
|
||||
timeout: timeout,
|
||||
};
|
||||
|
||||
let browser: any, page: any, server: any;
|
||||
if (process.env.CHROME_PATH) {
|
||||
opts = {
|
||||
...opts,
|
||||
executablePath: process.env.CHROME_PATH,
|
||||
};
|
||||
}
|
||||
|
||||
let browser: Browser;
|
||||
let page: Page;
|
||||
let server: ChildProcess;
|
||||
|
||||
let tlsnServerFixture: ChildProcess;
|
||||
const spawnTlsnServerFixture = () => {
|
||||
const tlsnServerFixturePath = './utils/tlsn/tlsn/tlsn-server-fixture/';
|
||||
// Spawn the server process
|
||||
// tlsnServerFixture = spawn(tlsnServerFixturePath, []);
|
||||
tlsnServerFixture = exec(`../target/release/main`, {
|
||||
cwd: tlsnServerFixturePath,
|
||||
});
|
||||
|
||||
tlsnServerFixture.stdout?.on('data', (data) => {
|
||||
console.log(`Server: ${data}`);
|
||||
});
|
||||
|
||||
tlsnServerFixture.stderr?.on('data', (data) => {
|
||||
console.error(`Server Error: ${data}`);
|
||||
});
|
||||
};
|
||||
|
||||
let localNotaryServer: ChildProcess;
|
||||
const spawnLocalNotaryServer = async () => {
|
||||
const localNotaryServerPath = './utils/tlsn/notary-server/';
|
||||
localNotaryServer = exec(`target/release/notary-server`, {
|
||||
cwd: localNotaryServerPath,
|
||||
});
|
||||
localNotaryServer.stdout?.on('data', (data) => {
|
||||
console.log(`Server: ${data}`);
|
||||
});
|
||||
|
||||
localNotaryServer.stderr?.on('data', (data) => {
|
||||
console.error(`Server Error: ${data}`);
|
||||
});
|
||||
|
||||
// wait for the notary server to be ready
|
||||
while (true) {
|
||||
try {
|
||||
const response = await fetch('http://127.0.0.1:7047/info');
|
||||
if (response.ok) {
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Waiting for local notary server...', error);
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
}
|
||||
};
|
||||
|
||||
const configureNotarySerer = () => {
|
||||
try {
|
||||
const configPath = './utils/tlsn/notary-server/config/config.yaml';
|
||||
const fileContents = fs.readFileSync(configPath, 'utf8');
|
||||
const data = yaml.load(fileContents) as any;
|
||||
data.tls.enabled = false;
|
||||
data.server.host = '127.0.0.1';
|
||||
const newYaml = yaml.dump(data);
|
||||
fs.writeFileSync(configPath, newYaml, 'utf8');
|
||||
console.log('YAML file has been updated.');
|
||||
} catch (error) {
|
||||
console.error('Error reading or updating the YAML file:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// expose variables
|
||||
before(async function () {
|
||||
server = exec('serve --config ../serve.json ./test-build -l 3001');
|
||||
|
||||
spawnTlsnServerFixture();
|
||||
configureNotarySerer();
|
||||
await spawnLocalNotaryServer();
|
||||
browser = await puppeteer.launch(opts);
|
||||
page = await browser.newPage();
|
||||
await page.goto('http://localhost:3001');
|
||||
await page.goto('http://127.0.0.1:3001');
|
||||
});
|
||||
|
||||
// close browser and reset global variables
|
||||
after(async function () {
|
||||
await server.kill();
|
||||
// @ts-ignore
|
||||
await browser.close();
|
||||
console.log('Cleaning up:');
|
||||
|
||||
try {
|
||||
tlsnServerFixture.kill();
|
||||
console.log('* Stopped TLSN Server Fixture ✅');
|
||||
|
||||
localNotaryServer.kill();
|
||||
console.log('* Stopped Notary Server ✅');
|
||||
|
||||
server.kill();
|
||||
console.log('* Stopped Test Web Server ✅');
|
||||
|
||||
await page.close();
|
||||
await browser.close();
|
||||
const childProcess = browser.process();
|
||||
if (childProcess) {
|
||||
childProcess.kill(9);
|
||||
}
|
||||
console.log('* Closed browser ✅');
|
||||
process.exit(0);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
||||
|
||||
describe('tlsn-js test suite', function () {
|
||||
it('should prove and verify swapi.dev', async function () {
|
||||
const content = await check('full-integration-swapi');
|
||||
const result = safeParseJson(content);
|
||||
assert(result.sent.includes('host: swapi.dev'));
|
||||
assert(result.sent.includes('secret: XXXXXXXXXXX'));
|
||||
assert(result.recv.includes('Luke Skywalker'));
|
||||
assert(result.recv.includes('"hair_color":"XXXXX"'));
|
||||
assert(result.recv.includes('"skin_color":"XXXX"'));
|
||||
});
|
||||
|
||||
it('should verify', async function () {
|
||||
const content = await check('simple-verify');
|
||||
const result = safeParseJson(content);
|
||||
assert(
|
||||
result.sent.includes(
|
||||
'user-agent: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
|
||||
),
|
||||
);
|
||||
assert(result.recv.includes('<h1>XXXXXXXXXXXXXX</h1>'));
|
||||
assert(result);
|
||||
fs.readdirSync(path.join(__dirname, 'specs')).forEach((file) => {
|
||||
const [id] = file.split('.');
|
||||
it(`Test ID: ${id}`, async function () {
|
||||
const content = await check(id);
|
||||
assert(content === 'OK');
|
||||
});
|
||||
});
|
||||
// it('should prove and verify data from the local tlsn-server-fixture', async function () {
|
||||
// const content = await check('full-integration-swapi');
|
||||
// assert(content === 'OK');
|
||||
// });
|
||||
//
|
||||
// it('should verify', async function () {
|
||||
// const content = await check('simple-verify');
|
||||
// assert(content === 'OK');
|
||||
// });
|
||||
});
|
||||
|
||||
async function check(testId: string): Promise<string> {
|
||||
const content = await page.$eval('#' + testId, (n: any) => n.innerText);
|
||||
if (content) return content;
|
||||
await new Promise((r) => setTimeout(r, 1000));
|
||||
return check(testId);
|
||||
}
|
||||
|
||||
function safeParseJson(data: string): any | null {
|
||||
try {
|
||||
return JSON.parse(data);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
const startTime = Date.now();
|
||||
const attemptFetchContent = async (): Promise<string> => {
|
||||
const content = await page.$eval(
|
||||
`#${testId}`,
|
||||
(el: any) => el.textContent || '',
|
||||
);
|
||||
if (content) return content;
|
||||
const elapsedTime = Date.now() - startTime;
|
||||
if (elapsedTime >= timeout) {
|
||||
throw new Error(
|
||||
`Timeout: Failed to retrieve content for '#${testId}' within ${timeout} ms.`,
|
||||
);
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
return attemptFetchContent();
|
||||
};
|
||||
return attemptFetchContent();
|
||||
}
|
||||
|
||||
3
test/utils.ts
Normal file
3
test/utils.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export function assert(expr: any, msg = 'unknown assertion error') {
|
||||
if (!Boolean(expr)) throw new Error(msg);
|
||||
}
|
||||
1
utils/.gitignore
vendored
Normal file
1
utils/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
tlsn
|
||||
32
utils/build-tlsn-binaries.sh
Executable file
32
utils/build-tlsn-binaries.sh
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
# Run tlsn Server fixture
|
||||
|
||||
# Set the directory to the location of the script
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# Name of the directory where the repo will be cloned
|
||||
REPO_DIR="tlsn"
|
||||
|
||||
# Check if the directory exists
|
||||
if [ ! -d "$REPO_DIR" ]; then
|
||||
# Clone the repository if it does not exist
|
||||
git clone https://github.com/tlsnotary/tlsn.git "$REPO_DIR"
|
||||
cd "$REPO_DIR"
|
||||
else
|
||||
# If the directory exists, just change to it
|
||||
cd "$REPO_DIR"
|
||||
# Fetch the latest changes in the repo without checkout
|
||||
git fetch
|
||||
fi
|
||||
|
||||
# Checkout the specific tag
|
||||
git checkout "v0.1.0-alpha.4"
|
||||
|
||||
for dir in "tlsn/tlsn-server-fixture/" "notary-server"; do
|
||||
# Change to the specific subdirectory
|
||||
cd ${dir}
|
||||
|
||||
# Build the project
|
||||
cargo build --release
|
||||
cd -
|
||||
done
|
||||
@@ -7,7 +7,8 @@ const isProd = process.env.NODE_ENV === 'production';
|
||||
|
||||
const envPlugin = new webpack.EnvironmentPlugin({
|
||||
NODE_ENV: 'development',
|
||||
LOCAL: false,
|
||||
LOCAL_NOTARY: true,
|
||||
LOCAL_WS: false,
|
||||
HEADLESS: false,
|
||||
});
|
||||
|
||||
@@ -37,8 +38,8 @@ module.exports = [
|
||||
target: 'web',
|
||||
mode: isProd ? 'production' : 'development',
|
||||
entry: {
|
||||
'full-integration-swapi.spec': path.join(__dirname, 'test', 'full-integration-swapi.spec.ts'),
|
||||
'simple-verify': path.join(__dirname, 'test', 'simple-verify.spec.ts'),
|
||||
'full-integration-swapi.spec': path.join(__dirname, 'test', 'specs', 'full-integration-swapi.spec.ts'),
|
||||
'simple-verify': path.join(__dirname, 'test', 'specs', 'simple-verify.spec.ts'),
|
||||
},
|
||||
output: {
|
||||
path: __dirname + '/test-build',
|
||||
|
||||
Reference in New Issue
Block a user