From 2c6068571268a41a5de530f9052f1de1faaafd24 Mon Sep 17 00:00:00 2001 From: Oleksii Kosynskyi Date: Mon, 20 Nov 2023 13:29:34 -0500 Subject: [PATCH] Stress Tests 2 - QA Tests (#6583) * add data stress test * fix unit tests * fix * try to fix validator test * fix ipc tests * fix load test * fix * move to tests folder * moved * fix * move validator test to web3 package * move to TS. remove time logs * fix start.sh * fix validation test run script * fix name --- package.json | 3 + .../web3-validator/test/unit/load.test.ts | 184 ------------------ packages/web3/test/stress/index.ts | 68 +++++++ packages/web3/test/stress/start.sh | 17 ++ packages/web3/test/stress/validator.ts | 126 ++++++++++++ scripts/geth_binary.sh | 17 +- 6 files changed, 229 insertions(+), 186 deletions(-) delete mode 100644 packages/web3-validator/test/unit/load.test.ts create mode 100644 packages/web3/test/stress/index.ts create mode 100755 packages/web3/test/stress/start.sh create mode 100644 packages/web3/test/stress/validator.ts diff --git a/package.json b/package.json index 8d5c00e2173..6adc68ec73b 100644 --- a/package.json +++ b/package.json @@ -85,6 +85,9 @@ "test:blackbox:geth:ws": "yarn pre-blackbox && yarn geth:start:background && ./scripts/verdaccio.sh startBackgroundAndPublish && lerna run test:blackbox:geth:ws --stream && yarn post-blackbox:geth", "test:blackbox:infura:http": "yarn pre-blackbox && ./scripts/verdaccio.sh startBackgroundAndPublish && lerna run test:blackbox:infura:http --stream && yarn post-blackbox", "test:blackbox:infura:ws": "yarn pre-blackbox && ./scripts/verdaccio.sh startBackgroundAndPublish && lerna run test:blackbox:infura:ws --stream && yarn post-blackbox", + "test:manual:stress:data": "packages/web3/test/stress/start.sh", + "test:manual:stress:validation": "npx ts-node packages/web3/test/stress/validator.ts", + "test:manual:stress": "yarn test:manual:stress:data && yarn test:manual:stress:validation", "husky:install": "husky install", "husky:uninstall": "husky uninstall", "postinstall": "yarn build", diff --git a/packages/web3-validator/test/unit/load.test.ts b/packages/web3-validator/test/unit/load.test.ts deleted file mode 100644 index 9053be7e8f0..00000000000 --- a/packages/web3-validator/test/unit/load.test.ts +++ /dev/null @@ -1,184 +0,0 @@ -/* -This file is part of web3.js. - -web3.js is free software: you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -web3.js is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with web3.js. If not, see . -*/ - -import { Web3Validator } from '../../src/web3_validator'; -import { Json, JsonSchema, ValidationSchemaInput } from '../../src/types'; - -const abi = [ - { indexed: true, internalType: 'address', name: 'from', type: 'address' }, - { indexed: true, internalType: 'address', name: 'to', type: 'address' }, - { indexed: false, internalType: 'uint256', name: 'value', type: 'uint256' }, -]; - -const abiJsonSchema = { - type: 'array', - items: [ - { name: 'from', format: 'address' }, - { name: 'to', format: 'address' }, - { name: 'value', format: 'uint256' }, - ], -}; - -const abiData = [ - '0xCB00CDE33a7a0Fba30C63745534F1f7Ae607076b', - '0xCB00CDE33a7a0Fba30C63745534F1f7Ae607076b', - '0xCB00CDE33a7a0Fba30C63745534F1f7Ae607076b', -]; - -const simpleSchema = { - type: 'object', - required: ['blockHash', 'blockNumber', 'from', 'to', 'data'], - properties: { - blockHash: { - format: 'bytes32', - }, - blockNumber: { - format: 'uint', - }, - from: { - format: 'address', - }, - to: { - oneOf: [{ format: 'address' }, { type: 'null' }], - }, - data: { - format: 'bytes', - }, - }, -}; - -const simpleData = { - blockHash: '0x0dec0518fa672a70027b04c286582e543ab17319fbdd384fa7bc8f3d5a542c0b', - blockNumber: BigInt(2), - from: '0xCB00CDE33a7a0Fba30C63745534F1f7Ae607076b', - to: '0xCB00CDE33a7a0Fba30C63745534F1f7Ae607076b', - data: '0xafea', -} as unknown as ValidationSchemaInput; - -const createHugeSchema = ( - schema: JsonSchema, - data: Json, - n = 3, -): { schema: JsonSchema; data: Json } => { - if (n > 0) { - const { data: resultData, schema: resultSchema } = createHugeSchema( - { ...simpleSchema } as JsonSchema, - { ...simpleData } as Json, - n - 1, - ); - return { - data: { ...(data as unknown as object), simple: resultData }, - schema: { ...schema, properties: { ...schema.properties, simple: resultSchema } }, - }; - } - return { - schema, - data, - }; -}; - -const { schema: hugeSchema, data: hugeData } = createHugeSchema( - { ...simpleSchema } as JsonSchema, - { ...simpleData } as Json, - 500, -); - -const { schema: hugeSchema1000, data: hugeData1000 } = createHugeSchema( - { ...simpleSchema } as JsonSchema, - { ...simpleData } as Json, - 1000, -); -describe('instance of validator', () => { - let validator: Web3Validator; - beforeAll(() => { - validator = new Web3Validator(); - }); - - it('huge schema', () => { - let t = 0; - expect(() => { - const t1 = Number(new Date()); - validator.validateJSONSchema(hugeSchema, hugeData as object); - t = Number(new Date()) - t1; - }).not.toThrow(); - expect(t).toBeLessThan(6000); - expect(t).toBeGreaterThan(0); - }); - - it('huge schema 1000', () => { - let t = 0; - expect(() => { - const t1 = Number(new Date()); - validator.validateJSONSchema(hugeSchema1000, hugeData1000 as object); - t = Number(new Date()) - t1; - }).not.toThrow(); - expect(t).toBeLessThan(6000); - expect(t).toBeGreaterThan(0); - }); - - it('simple schema multiple times', () => { - let t = 0; - expect(() => { - const t1 = Number(new Date()); - for (let i = 0; i < 500; i += 1) { - validator.validateJSONSchema(simpleSchema, simpleData as object); - } - t = Number(new Date()) - t1; - }).not.toThrow(); - expect(t).toBeLessThan(3000); - expect(t).toBeGreaterThan(0); - }); - - it('simple schema 1000 times', () => { - let t = 0; - expect(() => { - const t1 = Number(new Date()); - for (let i = 0; i < 1000; i += 1) { - validator.validateJSONSchema(simpleSchema, simpleData as object); - } - t = Number(new Date()) - t1; - }).not.toThrow(); - expect(t).toBeLessThan(4000); - expect(t).toBeGreaterThan(0); - }); - - it('simple JSON schema 1000 times', () => { - let t = 0; - expect(() => { - const t1 = Number(new Date()); - for (let i = 0; i < 1000; i += 1) { - validator.validateJSONSchema(abiJsonSchema, abiData as object); - } - t = Number(new Date()) - t1; - }).not.toThrow(); - expect(t).toBeLessThan(4000); - expect(t).toBeGreaterThan(0); - }); - - it('simple ABI 1000 times', () => { - let t = 0; - expect(() => { - const t1 = Number(new Date()); - for (let i = 0; i < 1000; i += 1) { - validator.validate(abi, abiData); - } - t = Number(new Date()) - t1; - }).not.toThrow(); - expect(t).toBeLessThan(4000); - expect(t).toBeGreaterThan(0); - }); -}); diff --git a/packages/web3/test/stress/index.ts b/packages/web3/test/stress/index.ts new file mode 100644 index 00000000000..67471e136fb --- /dev/null +++ b/packages/web3/test/stress/index.ts @@ -0,0 +1,68 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ + +/* eslint-disable */ +import { Web3 } from 'web3'; +import { IpcProvider } from 'web3-providers-ipc'; +import accounts from '../shared_fixtures/accounts.json'; +import { BasicAbi, BasicBytecode } from '../shared_fixtures/build/Basic'; +import WebSocketProvider from 'web3-providers-ws'; +const DATA_AMOUNT = 50 * 1024; // 50 kB + +const sendAndGetData = async (web3: Web3, i: number) => { + const sendOptions = { from: accounts[i].address }; + const deployOptions = { + data: BasicBytecode, + arguments: [0, ''] as [number, string], + gasPrice: await web3.eth.getGasPrice(), + gas: BigInt(9000000000000), + gasLimit: BigInt(9000000000000), + type: BigInt(0), + }; + const c = new web3.eth.Contract(BasicAbi); + const contract = await c.deploy(deployOptions).send(sendOptions); + + await contract.methods + // @ts-ignore + .setValues(1, 'A'.repeat(DATA_AMOUNT), true) + .send({ from: accounts[i].address }); + + await contract.methods.getStringValue().call(); +}; + +const test = async () => { + const providerString = String(process.env.WEB3_SYSTEM_TEST_PROVIDER); + console.log(`Start test with provider: ${providerString}`); + const provider = providerString.includes('ipc') + ? new IpcProvider(providerString) + : providerString; + const web3 = new Web3(provider); + + for (const a of accounts) { + const acc = web3.eth.accounts.privateKeyToAccount(a.privateKey); + web3.eth.accounts.wallet.add(acc); + } + + const prs = []; + for (let i = 0; i < 15; i++) { + prs.push(sendAndGetData(web3, i)); + } + await Promise.all(prs); + (web3.provider as unknown as WebSocketProvider).disconnect(); +}; + +test().catch(console.error); diff --git a/packages/web3/test/stress/start.sh b/packages/web3/test/stress/start.sh new file mode 100755 index 00000000000..9de30d524d9 --- /dev/null +++ b/packages/web3/test/stress/start.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +. scripts/env.sh + +export WEB3_SYSTEM_TEST_BACKEND="geth" +export TS_NODE_PREFER_TS_EXTS=true + +./scripts/geth_binary.sh stressStart + +yarn generate:accounts + +export WEB3_SYSTEM_TEST_PROVIDER=$IPC_PATH +npx ts-node ./packages/web3/test/stress/index.ts + +export WEB3_SYSTEM_TEST_PROVIDER=ws://127.0.0.1:8545 +npx ts-node ./packages/web3/test/stress/index.ts + +./scripts/geth_binary.sh stop diff --git a/packages/web3/test/stress/validator.ts b/packages/web3/test/stress/validator.ts new file mode 100644 index 00000000000..076351820c0 --- /dev/null +++ b/packages/web3/test/stress/validator.ts @@ -0,0 +1,126 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ + +/* eslint-disable */ +import { Web3Validator, JsonSchema, Json } from 'web3-validator'; + +const abi = [ + { indexed: true, internalType: 'address', name: 'from', type: 'address' }, + { indexed: true, internalType: 'address', name: 'to', type: 'address' }, + { indexed: false, internalType: 'uint256', name: 'value', type: 'uint256' }, +]; + +const abiJsonSchema = { + type: 'array', + items: [ + { name: 'from', format: 'address' }, + { name: 'to', format: 'address' }, + { name: 'value', format: 'uint256' }, + ], +}; + +const abiData = [ + '0xCB00CDE33a7a0Fba30C63745534F1f7Ae607076b', + '0xCB00CDE33a7a0Fba30C63745534F1f7Ae607076b', + '0xCB00CDE33a7a0Fba30C63745534F1f7Ae607076b', +]; + +const simpleSchema = { + type: 'object', + required: ['blockHash', 'blockNumber', 'from', 'to', 'data'], + properties: { + blockHash: { + format: 'bytes32', + }, + blockNumber: { + format: 'uint', + }, + from: { + format: 'address', + }, + to: { + oneOf: [{ format: 'address' }, { type: 'null' }], + }, + data: { + format: 'bytes', + }, + }, +}; + +const simpleData = { + blockHash: '0x0dec0518fa672a70027b04c286582e543ab17319fbdd384fa7bc8f3d5a542c0b', + blockNumber: BigInt(2), + from: '0xCB00CDE33a7a0Fba30C63745534F1f7Ae607076b', + to: '0xCB00CDE33a7a0Fba30C63745534F1f7Ae607076b', + data: '0xafea', +}; + +const createHugeSchema = ( + schema: JsonSchema, + data: Json, + n = 3, +): { schema: JsonSchema; data: Json } => { + if (n > 0) { + const { data: resultData, schema: resultSchema } = createHugeSchema( + { ...simpleSchema }, + { ...simpleData } as unknown as Json, + n - 1, + ); + return { + data: { ...(typeof data === 'object' ? data : { data }), simple: resultData }, + schema: { ...schema, properties: { ...schema.properties, simple: resultSchema } }, + }; + } + return { + schema, + data, + }; +}; + +const { schema: hugeSchema, data: hugeData } = createHugeSchema( + { ...simpleSchema }, + { ...simpleData } as unknown as Json, + 500, +); + +const { schema: hugeSchema1000, data: hugeData1000 } = createHugeSchema( + { ...simpleSchema }, + { ...simpleData } as unknown as Json, + 1000, +); + +const validator = new Web3Validator(); + +validator.validateJSONSchema(hugeSchema, hugeData as object); + +validator.validateJSONSchema(hugeSchema1000, hugeData1000 as object); + +for (let i = 0; i < 500; i += 1) { + validator.validateJSONSchema(simpleSchema, simpleData); +} + +for (let i = 0; i < 1000; i += 1) { + validator.validateJSONSchema(simpleSchema, simpleData); +} + +for (let i = 0; i < 1000; i += 1) { + validator.validateJSONSchema(abiJsonSchema, abiData); +} + +for (let i = 0; i < 1000; i += 1) { + validator.validate(abi, abiData); +} diff --git a/scripts/geth_binary.sh b/scripts/geth_binary.sh index 59f9bfecaea..82f48622ec6 100755 --- a/scripts/geth_binary.sh +++ b/scripts/geth_binary.sh @@ -59,17 +59,29 @@ start() { download if [ -z "${ORIGARGS[1]}" ]; then echo "Starting geth..." - echo "geth --ipcpath $IPC_PATH --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev --mine --dev.period=0 " + echo "geth --ipcpath $IPC_PATH --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev --mine --dev.period=0" ${TMP_FOLDER}/geth --ipcpath $IPC_PATH --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev --mine --dev.period=0 --rpc.enabledeprecatedpersonal else echo "Starting geth..." - echo "geth --ipcpath $IPC_PATH --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev --mine --dev.period=0 &>/dev/null &" + echo "geth --ipcpath $IPC_PATH --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev --mine --dev.period=0 &>/dev/null &" ${TMP_FOLDER}/geth --ipcpath $IPC_PATH --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev --mine --dev.period=0 --rpc.enabledeprecatedpersonal &>/dev/null & echo "Waiting for geth..." npx wait-port -t 10000 "$WEB3_SYSTEM_TEST_PORT" fi } +startStress() { + download + + echo "Starting geth..." + echo "geth --ipcpath $IPC_PATH --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev --mine --dev.period=0 --dev.gaslimit 9000000000000000 --rpc.txfeecap=1000000 &>/dev/null &" + ${TMP_FOLDER}/geth --ipcpath $IPC_PATH --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev --mine --dev.period=0 --rpc.enabledeprecatedpersonal --dev.gaslimit 9000000000000000 --rpc.txfeecap=1000000 &>/dev/null & + echo "Waiting for geth..." + npx wait-port -t 10000 "$WEB3_SYSTEM_TEST_PORT" + +} + + startSync() { download @@ -95,6 +107,7 @@ stop() { } case $1 in +stressStart) startStress ;; syncStart) startSync ;; syncStop) syncStop ;; start) start ;;