From ef2b78c1e5d5fa66773f48e2f4ca4a1c5dfd52f9 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Thu, 12 Dec 2024 08:31:29 +0100 Subject: [PATCH] tests --- .circleci/config.yml | 12 +-- .../src/app/components/generateProof.tsx | 2 +- .../src/plugins/circomElectronBasePlugin.ts | 9 +- apps/remixdesktop/src/tools/circom.ts | 60 ++++++------- .../test/tests/app/circom-compiler.test.ts | 86 +++++++++++++++++++ .../test/tests/app/circom-script.test.ts | 67 +++++++++++++++ 6 files changed, 197 insertions(+), 39 deletions(-) create mode 100644 apps/remixdesktop/test/tests/app/circom-compiler.test.ts create mode 100644 apps/remixdesktop/test/tests/app/circom-script.test.ts diff --git a/.circleci/config.yml b/.circleci/config.yml index 67b99229f6..beb801de8a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -107,23 +107,22 @@ jobs: test-remixdesktop-linux: machine: - image: ubuntu-2004:current + image: ubuntu-2204:current resource_class: xlarge working_directory: ~/remix-project parallelism: 15 steps: - run: ldd --version + - checkout - attach_workspace: at: . - run: unzip ./persist/desktopbuild.zip - run: command: | - nvm install 20.2 - nvm use 20.2 node -v - npm install --global yarn node-gyp + sudo npm install --global yarn node-gyp python -m pip install --upgrade pip pip install setuptools mkdir apps/remixdesktop/build @@ -136,14 +135,14 @@ jobs: - run: name: "Run tests" command: | - nvm use 20.2 cd apps/remixdesktop/ + nvm use 20.2 ./run_ci_test.sh - run: name: "Run isogit tests" command: | - nvm use 20.2 cd apps/remixdesktop/ + nvm use 20.2 ./run_git_ui_isogit_tests.sh - store_test_results: path: ./apps/remixdesktop/reports/tests @@ -521,6 +520,7 @@ jobs: ls -la dist/apps/remix-ide nvm install 20.2 nvm use 20.2 + /usr/sbin/softwareupdate --install-rosetta --agree-to-license - restore_cache: keys: - remixdesktop-deps-mac-{{ checksum "apps/remixdesktop/yarn.lock" }} diff --git a/apps/circuit-compiler/src/app/components/generateProof.tsx b/apps/circuit-compiler/src/app/components/generateProof.tsx index 84f3a018f0..25fcd77386 100644 --- a/apps/circuit-compiler/src/app/components/generateProof.tsx +++ b/apps/circuit-compiler/src/app/components/generateProof.tsx @@ -27,7 +27,7 @@ export function GenerateProof () { className="btn btn-secondary btn-block d-block w-100 text-break mb-1 mt-1" onClick={() => generateProof(circuitApp.plugin, circuitApp.appState, circuitApp.dispatch)} disabled={(status === "compiling") || (status === "computing") || (status === "proving") || (status === "exporting")} - data-id="compute_witness_btn" + data-id="generateProofBtn" > diff --git a/apps/remixdesktop/src/plugins/circomElectronBasePlugin.ts b/apps/remixdesktop/src/plugins/circomElectronBasePlugin.ts index f15134eaab..f8b73c43a2 100644 --- a/apps/remixdesktop/src/plugins/circomElectronBasePlugin.ts +++ b/apps/remixdesktop/src/plugins/circomElectronBasePlugin.ts @@ -35,6 +35,8 @@ class CircomElectronPluginClient extends ElectronBasePluginClient { } async install(version = 'latest') { + this.call('terminal' as any, 'logHtml', `Checking if circom compiler (${version}) is installed in ${getInstallationPath(version)}`) + this.isCircomInstalled = await circomCli.isCircomInstalled(version) if (!this.isCircomInstalled) { this.call('terminal' as any, 'logHtml', 'Downloading circom compiler from ' + getInstallationUrl(version)) @@ -56,8 +58,11 @@ class CircomElectronPluginClient extends ElectronBasePluginClient { else { // @ts-ignore if (process.platform === 'win32' && 'wasm' in options) { - // @ts-ignore - await this.call('fs', 'rmdir', path.join(extractParentFromKey(filePath), '.bin', extractNameFromKey(filePath).replace('.circom', '_js'))) + try{ + // @ts-ignore + await this.call('fs', 'rmdir', path.join(extractParentFromKey(filePath), '.bin', extractNameFromKey(filePath).replace('.circom', '_js'))) + } catch (e) { + } } } filePath = path.join(wd, filePath) diff --git a/apps/remixdesktop/src/tools/circom.ts b/apps/remixdesktop/src/tools/circom.ts index a6cbb1651b..1d3c68e099 100644 --- a/apps/remixdesktop/src/tools/circom.ts +++ b/apps/remixdesktop/src/tools/circom.ts @@ -1,4 +1,5 @@ import { app } from 'electron' +import os from 'os' import { exec } from 'child_process' import path from 'path' import fs, { existsSync } from 'fs' @@ -33,16 +34,13 @@ async function downloadFile(url: string, dest: string) { } export function getInstallationPath(version) { - switch (process.platform) { - case 'win32': - return process.env.NODE_ENV === 'production' ? path.join(app.getPath('temp'), 'circom-download', version, 'circom-windows-amd64.exe') : path.join(app.getAppPath(), 'circom-download', version, 'circom-windows-amd64.exe') - - case 'darwin': - return process.env.NODE_ENV === 'production' ? path.join(app.getPath('temp'), 'circom-download', version, 'circom-macos-amd64') : path.join(app.getAppPath(), 'circom-download', version, 'circom-macos-amd64') - - case 'linux': - return process.env.NODE_ENV === 'production' ? path.join(app.getPath('temp'), 'circom-download', version, 'circom-linux-amd64') : path.join(app.getAppPath(), 'circom-download', version, 'circom-linux-amd64') - } + const fileNames = { + win32: 'circom-windows-amd64.exe', + darwin: 'circom-macos-amd64', + linux: 'circom-linux-amd64' + }; + + return path.join(os.tmpdir(), 'circom-download', version, fileNames[process.platform]); } export function getInstallationUrl(version) { @@ -59,25 +57,9 @@ export function getInstallationUrl(version) { } export function getLogInputSignalsPath() { - console.log('home: ', app.getPath('home')) - console.log('appData: ', app.getPath('appData')) - console.log('userData: ', app.getPath('userData')) - console.log('temp: ', app.getPath('temp')) - console.log('exe: ', app.getPath('exe')) - console.log('getAppPath: ', app.getAppPath()) - switch (process.platform) { - case 'win32': - // eslint-disable-next-line no-case-declarations - const programDir = app.getPath('exe').split('\\').slice(0, -1).join('\\') - - return process.env.NODE_ENV === 'production' ? path.join(programDir, 'log_input_signals.txt') : path.join(app.getAppPath(), 'log_input_signals.txt') - - case 'darwin': - return path.join(app.getAppPath(), 'log_input_signals.txt') - case 'linux': - return process.env.NODE_ENV === 'production' ? path.join(app.getPath('temp'), 'log_input_signals.txt') : path.join(app.getAppPath(), 'log_input_signals.txt') - } + const tempFilePath = path.join(os.tmpdir(), 'log_input_signals.txt'); + return tempFilePath; } export const circomCli = { @@ -106,9 +88,15 @@ export const circomCli = { async run (filePath: string, version: string, options?: Record) { const installationPath = getInstallationPath(version) const cmd = `${installationPath} ${filePath} ${Object.keys(options || {}).map((key) => options[key] ? `--${key} ${options[key]}` : `--${key}`).join(' ')}` - + console.log(cmd) + if(process.platform === 'darwin') { + const rosettaInstalled = await checkRosettaInstalled(); + if(rosettaInstalled === 'Rosetta is not installed') { + throw new Error('Rosetta is not installed. Please install Rosetta to run this command.'); + } + } return new Promise((resolve, reject) => { - exec(cmd, (error, stdout, stderr) => { + exec(cmd, { cwd: os.tmpdir() }, (error, stdout, stderr) => { if (error) { reject(`${error.message} with error code ${error.code}`) } else { @@ -134,3 +122,15 @@ export const extractNameFromKey = (key: string): string => { return keyPath[keyPath.length - 1] } + +async function checkRosettaInstalled(): Promise { + return new Promise((resolve, reject) => { + exec("/usr/bin/pgrep oahd > /dev/null && echo 'Rosetta is installed' || echo 'Rosetta is not installed'", (error, stdout, stderr) => { + if (error) { + reject(`Error: ${stderr}`); + } else { + resolve(stdout.trim()); + } + }); + }); +} diff --git a/apps/remixdesktop/test/tests/app/circom-compiler.test.ts b/apps/remixdesktop/test/tests/app/circom-compiler.test.ts new file mode 100644 index 0000000000..eec7885f5f --- /dev/null +++ b/apps/remixdesktop/test/tests/app/circom-compiler.test.ts @@ -0,0 +1,86 @@ +import { NightwatchBrowser } from "nightwatch" + + +const tests = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + browser.hideToolTips() + done() + }, + 'Should create semaphore workspace': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="homeTabGetStartedsemaphore"]', 20000) + .click('*[data-id="homeTabGetStartedsemaphore"]') + .pause(3000) + .windowHandles(function (result) { + console.log(result.value) + browser.switchWindow(result.value[1]) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemcircuits"]') + .click('*[data-id="treeViewLitreeViewItemcircuits"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemcircuits/semaphore.circom"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts"]') + .click('*[data-id="treeViewLitreeViewItemscripts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/groth16"]') + .click('*[data-id="treeViewLitreeViewItemscripts/groth16"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/groth16/groth16_trusted_setup.ts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/groth16/groth16_zkproof.ts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/plonk"]') + .click('*[data-id="treeViewLitreeViewItemscripts/plonk"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/plonk/plonk_trusted_setup.ts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/plonk/plonk_zkproof.ts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtemplates"]') + .click('*[data-id="treeViewLitreeViewItemtemplates"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtemplates/groth16_verifier.sol.ejs"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtemplates/plonk_verifier.sol.ejs"]') + }) + }, + 'Should compile a simple circuit using editor play button': function (browser: NightwatchBrowser) { + browser + .click('[data-id="treeViewLitreeViewItemcircuits/simple.circom"]') + .waitForElementVisible('[data-id="play-editor"]') + .click('[data-id="play-editor"]') + .pause(3000) + .click('[data-id="play-editor"]') + .waitForElementVisible('[data-id="verticalIconsKindcircuit-compiler"]') + .waitForElementVisible('[data-id="treeViewLitreeViewItemcircuits/.bin"]') + .click('[data-id="treeViewLitreeViewItemcircuits/.bin"]') + .waitForElementVisible('[data-id="treeViewLitreeViewItemcircuits/.bin/simple_js"]') + .click('[data-id="treeViewLitreeViewItemcircuits/.bin/simple_js"]') + .waitForElementVisible('[data-id="treeViewLitreeViewItemcircuits/.bin/simple_js/simple.wasm"]') + }, + 'Should run setup script for simple circuit': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('circuit-compiler') + .frame(0) + .waitForElementVisible('[data-id="runSetupBtn"]') + .click('[data-id="runSetupBtn"]') + }, + 'Should compute a witness for a simple circuit': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('[data-id="compute_witness_btn"]', 60000) + .waitForElementVisible('[data-id="circuit_input_a"]') + .waitForElementVisible('[data-id="circuit_input_b"]') + .setValue('[data-id="circuit_input_a"]', '1') + .setValue('[data-id="circuit_input_b"]', '2') + .click('[data-id="compute_witness_btn"]') + .frameParent() + .clickLaunchIcon('filePanel') + .waitForElementPresent('[data-id="treeViewLitreeViewItemcircuits/.bin/simple_js/simple.wtn"]') + .waitForElementVisible('[data-id="treeViewLitreeViewItemcircuits/.bin/simple_js/simple.wtn"]') + }, + 'Should generate proof for a simple circuit': function (browser: NightwatchBrowser) { + browser + .clickLaunchIcon('circuit-compiler') + .frame(0) + .waitForElementVisible('[data-id="generateProofBtn"]') + .click('[data-id="generateProofBtn"]') + .frameParent() + .waitForElementVisible({ + locateStrategy: 'xpath', + selector: "//span[@class='text-log' and contains(., 'zk proof validity true')]", + timeout: 60000 + }) + + } +} + +module.exports = tests diff --git a/apps/remixdesktop/test/tests/app/circom-script.test.ts b/apps/remixdesktop/test/tests/app/circom-script.test.ts new file mode 100644 index 0000000000..c9aebb899d --- /dev/null +++ b/apps/remixdesktop/test/tests/app/circom-script.test.ts @@ -0,0 +1,67 @@ +import { NightwatchBrowser } from "nightwatch" + + +const tests = { + before: function (browser: NightwatchBrowser, done: VoidFunction) { + browser.hideToolTips() + done() + }, + 'Should create semaphore workspace': function (browser: NightwatchBrowser) { + browser + .waitForElementVisible('*[data-id="homeTabGetStartedsemaphore"]', 20000) + .click('*[data-id="homeTabGetStartedsemaphore"]') + .pause(3000) + .windowHandles(function (result) { + console.log(result.value) + browser.switchWindow(result.value[1]) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemcircuits"]') + .click('*[data-id="treeViewLitreeViewItemcircuits"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemcircuits/semaphore.circom"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts"]') + .click('*[data-id="treeViewLitreeViewItemscripts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/groth16"]') + .click('*[data-id="treeViewLitreeViewItemscripts/groth16"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/groth16/groth16_trusted_setup.ts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/groth16/groth16_zkproof.ts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/plonk"]') + .click('*[data-id="treeViewLitreeViewItemscripts/plonk"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/plonk/plonk_trusted_setup.ts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/plonk/plonk_zkproof.ts"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtemplates"]') + .click('*[data-id="treeViewLitreeViewItemtemplates"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtemplates/groth16_verifier.sol.ejs"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemtemplates/plonk_verifier.sol.ejs"]') + }) + }, + 'Should run plonk trusted setup script for hash checker #group6': function (browser: NightwatchBrowser) { + browser + .click('[data-id="treeViewLitreeViewItemscripts/plonk/plonk_trusted_setup.ts"]') + .pause(2000) + .click('[data-id="play-editor"]') + .waitForElementVisible('[data-id="verticalIconsKindcircuit-compiler"]') + .waitForElementVisible({ + locateStrategy: 'xpath', + selector: "//span[@class='text-log' and contains(., 'setup done.')]", + timeout: 60000 + }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/plonk/zk"]') + .click('*[data-id="treeViewLitreeViewItemscripts/plonk/zk"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/plonk/zk/keys"]') + .click('*[data-id="treeViewLitreeViewItemscripts/plonk/zk/keys"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemscripts/plonk/zk/keys/verification_key.json"]') + }, + 'Should run plonk zkproof script for hash checker #group6': function (browser: NightwatchBrowser) { + browser + .click('[data-id="treeViewLitreeViewItemscripts/plonk/plonk_zkproof.ts"]') + .pause(2000) + .click('[data-id="play-editor"]') + .waitForElementVisible({ + locateStrategy: 'xpath', + selector: "//span[@class='text-log' and contains(., 'proof done')]", + timeout: 60000 + }) + } + +} + +module.exports = {}