Skip to content

Commit

Permalink
chore(ci): Nightly Integration testing (#2596)
Browse files Browse the repository at this point in the history
Co-authored-by: Tom French <[email protected]>
Co-authored-by: Tom French <[email protected]>
  • Loading branch information
3 people authored Sep 11, 2023
1 parent 7cdff2e commit dedcf5e
Show file tree
Hide file tree
Showing 7 changed files with 4,598 additions and 0 deletions.
11 changes: 11 additions & 0 deletions .github/NIGHTLY_TEST_FAILURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
title: "nightly test-integration failed"
assignees: kobyhallx, phated, tomafrench, jonybur
labels: bug
---

Something broke our nightly integration test.

Check the [test]({{env.WORKFLOW_URL}}) workflow for details.

This issue was raised by the workflow `{{env.WORKFLOW_NAME}}`
113 changes: 113 additions & 0 deletions .github/workflows/test-integration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
name: test-integration

on:
workflow_dispatch:
schedule:
- cron: "0 2 * * *" # Run nightly at 2 AM UTC

jobs:
wasm-packages-build-test:
runs-on: ubuntu-latest
env:
CACHED_PATH: /tmp/nix-cache

steps:
- name: Checkout noir sources
uses: actions/checkout@v4

- name: Checkout acvm sources
uses: actions/checkout@v3 # v3 is needed here otherwise this fails in local execution
with:
repository: noir-lang/acvm
path: acvm

- name: Setup Nix
uses: cachix/install-nix-action@v22
with:
nix_path: nixpkgs=channel:nixos-23.05
github_access_token: ${{ secrets.GITHUB_TOKEN }}

- uses: cachix/cachix-action@v12
with:
name: barretenberg
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"

- name: Restore nix store cache
uses: actions/cache/restore@v3
id: cache
with:
path: ${{ env.CACHED_PATH }}
key: ${{ runner.os }}-flake-wasm-${{ hashFiles('*.lock') }}

# Based on https://github.com/marigold-dev/deku/blob/b5016f0cf4bf6ac48db9111b70dd7fb49b969dfd/.github/workflows/build.yml#L26
- name: Copy cache into nix store
if: steps.cache.outputs.cache-hit == 'true'
# We don't check the signature because we're the one that created the cache
run: |
for narinfo in ${{ env.CACHED_PATH }}/*.narinfo; do
path=$(head -n 1 "$narinfo" | awk '{print $2}')
nix copy --no-check-sigs --from "file://${{ env.CACHED_PATH }}" "$path"
done
- name: Build noir_wasm package
run: |
nix build -L .#wasm
mkdir -p ./.packages/noir_wasm
cp -r ./result/* ./.packages/noir_wasm/
echo "UPLOAD_PATH=$(readlink -f result)" >> $GITHUB_ENV
- name: Upload `noir_wasm` artifact
uses: actions/upload-artifact@v3
with:
name: noir_wasm
path: ${{ env.UPLOAD_PATH }}
retention-days: 3

- name: Build noirc_abi_wasm package
run: |
nix build -L .#noirc_abi_wasm
mkdir -p ./.packages/noirc_abi_wasm
cp -r ./result/* ./.packages/noirc_abi_wasm/
echo "UPLOAD_PATH=$(readlink -f result)" >> $GITHUB_ENV
- name: Upload `noirc_abi_wasm` artifact
uses: actions/upload-artifact@v3
with:
name: noirc_abi_wasm
path: ${{ env.UPLOAD_PATH }}
retention-days: 3

- name: Build `acvm_js` package
working-directory: ./acvm
run: |
nix build -L .#
mkdir -p ../.packages/acvm_js
cp -r ./result/* ../.packages/acvm_js/
echo "UPLOAD_PATH=$(readlink -f result)" >> $GITHUB_ENV
- name: Upload `acvm_js` artifact
uses: actions/upload-artifact@v3
with:
name: acvm_js
path: ${{ env.UPLOAD_PATH }}
retention-days: 3

- name: Install `integration-tests` dependencies
working-directory: ./crates/integration-tests
run: yarn install

- name: Run `integration-tests`
working-directory: ./crates/integration-tests
run: |
yarn test:browser
- name: Alert on nightly test failure
uses: JasonEtco/create-an-issue@v2
if: ${{ failure() && github.event_name == 'schedule' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
WORKFLOW_NAME: ${{ github.workflow }}
WORKFLOW_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
with:
update_existing: true
filename: .github/NIGHTLY_TEST_FAILURE.md
19 changes: 19 additions & 0 deletions crates/integration-tests/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module.exports = {
root: true,
parser: "@typescript-eslint/parser",
plugins: ["@typescript-eslint", "prettier"],
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
rules: {
"comma-spacing": ["error", { before: false, after: true }],
// "no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"warn", // or "error"
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_",
},
],
"prettier/prettier": "error",
}
};
35 changes: 35 additions & 0 deletions crates/integration-tests/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "integration-tests",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' mocha",
"test:browser": "web-test-runner",
"test:node": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' mocha",
"test:integration:browser": "web-test-runner test//integration/browser/**/*.test.ts",
"test:integration:browser:watch": "web-test-runner test/integration/browser/**/*.test.ts --watch"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@esm-bundle/chai": "^4.3.4-fix.0",
"@web/dev-server-esbuild": "^0.3.6",
"@web/test-runner": "^0.15.3",
"@web/test-runner-webdriver": "^0.7.0",
"chai": "^4.3.7",
"fflate": "^0.8.0",
"mocha": "^10.2.0",
"smol-toml": "^1.1.2",
"ts-node": "^10.9.1",
"typescript": "^5.0.4"
},
"dependencies": {
"@aztec/bb.js": "^0.5.1",
"@noir-lang/acvm_js": "./../../.packages/acvm_js",
"@noir-lang/noir-source-resolver": "^1.1.4",
"@noir-lang/noir_wasm": "./../../.packages/noir_wasm",
"@noir-lang/noirc_abi": "./../../.packages/noirc_abi_wasm"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import { expect } from '@esm-bundle/chai';
import { initialiseResolver } from "@noir-lang/noir-source-resolver";
import newCompiler, {
compile,
init_log_level as compilerLogLevel
} from "@noir-lang/noir_wasm";
import { decompressSync as gunzip } from 'fflate';
import newABICoder, { abiEncode } from "@noir-lang/noirc_abi";
import initACVM, {
executeCircuit,
WitnessMap,
compressWitness,
} from "@noir-lang/acvm_js";

// @ts-ignore
import { Barretenberg, RawBuffer, Crs } from '@aztec/bb.js';

import * as TOML from 'smol-toml'


await newCompiler();
await newABICoder();
await initACVM();

compilerLogLevel("DEBUG");

async function getFile(url: URL): Promise<string> {

const response = await fetch(url)

if (!response.ok) throw new Error('Network response was not OK');

return await response.text();
}

const CIRCUIT_SIZE = 2 ** 19;


const test_cases = [
{
case: "crates/nargo_cli/tests/execution_success/1_mul"
},
{
case: "crates/nargo_cli/tests/execution_success/double_verify_proof"
}
];

const numberOfThreads = navigator.hardwareConcurrency || 1;

let suite = Mocha.Suite.create(mocha.suite, "Noir end to end test");

suite.timeout(60*10e3);//10mins

test_cases.forEach((testInfo) => {
const test_name = testInfo.case.split("/").pop();
const mochaTest = new Mocha.Test(`${test_name} (Compile, Execute, Proove, Verify)`, async () => {

const base_relative_path = "../../../../..";
const test_case = testInfo.case;

const noir_source_url = new URL(`${base_relative_path}/${test_case}/src/main.nr`, import.meta.url);
const prover_toml_url = new URL(`${base_relative_path}/${test_case}/Prover.toml`, import.meta.url);

const noir_source = await getFile(noir_source_url);
const prover_toml = await getFile(prover_toml_url);

expect(noir_source).to.be.a.string;

initialiseResolver((id: String) => {
console.log("Resoving:", id);
return noir_source;
});

const inputs = TOML.parse(prover_toml);

expect(inputs, "Prover.toml").to.be.an('object');

let compile_output;

try {

compile_output = await compile({});

expect(await compile_output, "Compile output ").to.be.an('object');

} catch (e) {
expect(e, "Compilation Step").to.not.be.an('error');
throw e;
}


let witnessMap: WitnessMap;
try {

witnessMap = abiEncode(compile_output.abi, inputs, null);

} catch (e) {
expect(e, "Abi Encoding Step").to.not.be.an('error');
throw e;
}

let solvedWitness: WitnessMap;
let compressedByteCode;
try {
compressedByteCode = Uint8Array.from(atob(compile_output.circuit), c => c.charCodeAt(0));

solvedWitness = await executeCircuit(
compressedByteCode,
witnessMap,
() => {
throw Error("unexpected oracle");
}
);

} catch (e) {
expect(e, "Abi Encoding Step").to.not.be.an('error');
throw e;
}

try {
const compressedWitness = compressWitness(solvedWitness);
const acirUint8Array = gunzip(compressedByteCode);
const witnessUint8Array = gunzip(compressedWitness);

const isRecursive = true;
const api = await Barretenberg.new(numberOfThreads);
await api.commonInitSlabAllocator(CIRCUIT_SIZE);

// Plus 1 needed!
const crs = await Crs.new(CIRCUIT_SIZE + 1);
await api.srsInitSrs(new RawBuffer(crs.getG1Data()), crs.numPoints, new RawBuffer(crs.getG2Data()));

const acirComposer = await api.acirNewAcirComposer(CIRCUIT_SIZE);

const proof = await api.acirCreateProof(
acirComposer,
acirUint8Array,
witnessUint8Array,
isRecursive
);


const verified = await api.acirVerifyProof(acirComposer, proof, isRecursive);

expect(verified).to.be.true;

} catch (e) {
expect(e, "Proving and Verifying").to.not.be.an('error');
throw e;
}

});

suite.addTest(mochaTest);

});
32 changes: 32 additions & 0 deletions crates/integration-tests/web-test-runner.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { fileURLToPath } from 'url';
import { esbuildPlugin } from "@web/dev-server-esbuild";
import { webdriverLauncher } from '@web/test-runner-webdriver';

export default {
browsers: [
webdriverLauncher({
automationProtocol: 'webdriver',
capabilities: {
browserName: 'firefox',
'moz:firefoxOptions': {
args: ['-headless'],
},
},
}),

],
plugins: [
esbuildPlugin({
ts: true,
}),
],
files: ["test/integration/browser/**/*.test.ts"],
nodeResolve: { browser: true },
testFramework: {
config: {
ui: "bdd",
},
},
rootDir: fileURLToPath(new URL('./../..', import.meta.url)),

};
Loading

0 comments on commit dedcf5e

Please sign in to comment.