Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(ci): Nightly Integration testing #2596

Merged
merged 19 commits into from
Sep 11, 2023
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
kevaundray marked this conversation as resolved.
Show resolved Hide resolved

- 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"
kevaundray marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
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"
},
// Below fails
TomAFrench marked this conversation as resolved.
Show resolved Hide resolved
{
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