diff --git a/k6/.gitignore b/k6/.gitignore new file mode 100644 index 0000000000..28ad22916c --- /dev/null +++ b/k6/.gitignore @@ -0,0 +1 @@ +src/prepare/.smartContractParams.json diff --git a/k6/package-lock.json b/k6/package-lock.json index 3668e2af07..dda68bfabb 100644 --- a/k6/package-lock.json +++ b/k6/package-lock.json @@ -10,6 +10,9 @@ "dependencies": { "env-cmd": "^10.1.0", "ethers": "^6.13.2" + }, + "devDependencies": { + "@types/k6": "^0.53.1" } }, "node_modules/@adraffy/ens-normalize": { @@ -42,6 +45,13 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@types/k6": { + "version": "0.53.1", + "resolved": "https://registry.npmjs.org/@types/k6/-/k6-0.53.1.tgz", + "integrity": "sha512-Mm1+7kESDNssyBiMV+5MVAJKwpJbj1Y3X1YkCDlaiPbjuc8DeaPtQFBv3pnip/0ZjM9P/P/aDNvd4BvQT0lQDg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { "version": "18.15.13", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", diff --git a/k6/package.json b/k6/package.json index aa26e7afe8..3ae6fe12d3 100644 --- a/k6/package.json +++ b/k6/package.json @@ -6,10 +6,14 @@ "scripts": { "prep-and-run": "npm run prep && npm run k6", "prep": "env-cmd node src/prepare/prep.js", - "k6": "env-cmd --use-shell k6 run src/scenarios/apis.js" + "k6": "env-cmd --use-shell k6 run src/scenarios/apis.js", + "k6-ws": "env-cmd --use-shell k6 run src/scenarios/ws-apis.js" }, "dependencies": { "env-cmd": "^10.1.0", "ethers": "^6.13.2" + }, + "devDependencies": { + "@types/k6": "^0.53.1" } } diff --git a/k6/src/scenarios/test/bootstrapEnvParameters.js b/k6/src/lib/bootstrapEnvParameters.js similarity index 93% rename from k6/src/scenarios/test/bootstrapEnvParameters.js rename to k6/src/lib/bootstrapEnvParameters.js index 6cc44ecd47..8332b61193 100644 --- a/k6/src/scenarios/test/bootstrapEnvParameters.js +++ b/k6/src/lib/bootstrapEnvParameters.js @@ -23,9 +23,9 @@ import { computeLatestEthereumTransactionParameters, computeLatestLogParameters, setDefaultValuesForEnvParameters, -} from '../../lib/parameters.js'; +} from './parameters.js'; -const scParams = JSON.parse(open('../../prepare/.smartContractParams.json')); +const scParams = JSON.parse(open('../prepare/.smartContractParams.json')); const computeTestParameters = (configuration) => Object.assign( diff --git a/k6/src/lib/common.js b/k6/src/lib/common.js index 833bab29de..f0a25e45ef 100644 --- a/k6/src/lib/common.js +++ b/k6/src/lib/common.js @@ -206,6 +206,13 @@ function markdownReport(data, isFirstColumnUrl, scenarios) { // collect the metrics const { metrics } = data; + + const isDebugMode = __ENV['DEBUG_MODE'] === 'true'; + if (isDebugMode) { + console.log("Raw metrics:"); + console.log(JSON.stringify(metrics, null, 2)); + } + const scenarioMetrics = {}; for (const [key, value] of Object.entries(metrics)) { diff --git a/k6/src/lib/constants.js b/k6/src/lib/constants.js index fb7adbcba2..8ae217aa94 100644 --- a/k6/src/lib/constants.js +++ b/k6/src/lib/constants.js @@ -21,3 +21,8 @@ export const logListName = 'logs'; export const resultListName = 'results'; export const transactionListName = 'transactions'; +export const subscribeEvents = { + logs: 'logs', + newHeads: 'newHeads', + newPendingTransactions: 'newPendingTransactions', +}; diff --git a/k6/src/prepare/contracts/Greeter.sol b/k6/src/prepare/contracts/Greeter.sol new file mode 100644 index 0000000000..97071fb3a4 --- /dev/null +++ b/k6/src/prepare/contracts/Greeter.sol @@ -0,0 +1,24 @@ +//SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.0; + +contract Greeter { + string private greeting; + + event GreetingSet(string greeting); + + constructor(string memory _greeting) { + greeting = _greeting; + + emit GreetingSet(_greeting); + } + + function greet() public view returns (string memory) { + return greeting; + } + + function setGreeting(string memory _greeting) public { + greeting = _greeting; + + emit GreetingSet(_greeting); + } +} diff --git a/k6/src/prepare/prep.js b/k6/src/prepare/prep.js index b0eb866bb6..6dba77abbe 100644 --- a/k6/src/prepare/prep.js +++ b/k6/src/prepare/prep.js @@ -1,5 +1,25 @@ +/* + * + * Hedera JSON RPC Relay + * + * Copyright (C) 2022-2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import Greeter from './contracts/Greeter.json' assert { type: 'json' }; -import { ethers } from 'ethers'; +import { ethers, formatEther, parseEther } from 'ethers'; import * as fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; @@ -9,8 +29,8 @@ const __dirname = path.dirname(__filename); const logPayloads = process.env.DEBUG_MODE === 'true'; -class LoggingProvider extends ethers.providers.JsonRpcProvider { - send(method, params) { +class LoggingProvider extends ethers.JsonRpcProvider { + async send(method, params) { if (logPayloads) { const request = { method: method, @@ -45,7 +65,7 @@ async function getSignedTxs(wallet, greeterContracts, gasPrice, gasLimit, chainI const greeterContractAddress = randomIntFromInterval(0, greeterContracts.length - 1); const greeterContract = new ethers.Contract(greeterContracts[greeterContractAddress], Greeter.abi, wallet); const msg = `Greetings from Automated Test Number ${i}, Hello!`; - const trx = await greeterContract.populateTransaction.setGreeting(msg); + const trx = await greeterContract['setGreeting'].populateTransaction(msg); trx.gasLimit = gasLimit; trx.chainId = chainId; trx.gasPrice = gasPrice; @@ -59,13 +79,13 @@ async function getSignedTxs(wallet, greeterContracts, gasPrice, gasLimit, chainI } (async () => { - const provider = new ethers.providers.JsonRpcProvider(process.env.RELAY_BASE_URL); + const provider = new LoggingProvider(process.env.RELAY_BASE_URL); const mainPrivateKeyString = process.env.PRIVATE_KEY; - const mainWallet = new ethers.Wallet(mainPrivateKeyString, new LoggingProvider(process.env.RELAY_BASE_URL)); + const mainWallet = new ethers.Wallet(mainPrivateKeyString, provider); console.log('RPC Server: ' + process.env.RELAY_BASE_URL); console.log('Main Wallet Address: ' + mainWallet.address); console.log( - 'Main Wallet Initial Balance: ' + ethers.utils.formatEther(await provider.getBalance(mainWallet.address)) + ' HBAR', + 'Main Wallet Initial Balance: ' + formatEther(await provider.getBalance(mainWallet.address)) + ' HBAR', ); const usersCount = process.env.WALLETS_AMOUNT ? process.env.WALLETS_AMOUNT : 1; const contractsCount = process.env.SMART_CONTRACTS_AMOUNT ? process.env.SMART_CONTRACTS_AMOUNT : 1; @@ -74,20 +94,19 @@ async function getSignedTxs(wallet, greeterContracts, gasPrice, gasLimit, chainI const contractFactory = new ethers.ContractFactory(Greeter.abi, Greeter.bytecode, mainWallet); console.log(`Deploying Greeter SC ${i}`); const contract = await contractFactory.deploy('Hey World!'); - const contractAddress = contract.address; + await contract.waitForDeployment(); + const contractAddress = contract.target; console.log(`Greeter SC Address: ${contractAddress}`); smartContracts.push(contractAddress); } const wallets = []; - const chainId = await mainWallet.getChainId(); + const chainId = (await provider.getNetwork()).chainId; const msgForEstimate = `Greetings from Automated Test Number i, Hello!`; const contractForEstimate = new ethers.Contract(smartContracts[0], Greeter.abi, mainWallet); - const gasLimit = ethers.utils.hexValue( - Math.round((await contractForEstimate.estimateGas.setGreeting(msgForEstimate)) * 1.5), - ); // extra - const gasPrice = ethers.utils.hexValue(Math.round((await mainWallet.getGasPrice()) * 1.5)); // with extra + const gasLimit = await contractForEstimate['setGreeting'].estimateGas(msgForEstimate); + const gasPrice = (await provider.getFeeData()).gasPrice; for (let i = 0; i < usersCount; i++) { const wallet = ethers.Wallet.createRandom(); @@ -102,7 +121,7 @@ async function getSignedTxs(wallet, greeterContracts, gasPrice, gasLimit, chainI let tx = { to: wallet.address, // Convert currency unit from ether to wei - value: ethers.utils.parseEther(amountInEther), + value: parseEther(amountInEther), }; // Send transaction @@ -111,7 +130,7 @@ async function getSignedTxs(wallet, greeterContracts, gasPrice, gasLimit, chainI }); const balance = await provider.getBalance(wallet.address); - console.log('balance: ', ethers.utils.formatEther(balance)); + console.log('balance: ', formatEther(balance)); const walletProvider = new ethers.Wallet(wallet.privateKey, new LoggingProvider(process.env.RELAY_BASE_URL)); const signedTxCollection = await getSignedTxs(walletProvider, smartContracts, gasPrice, gasLimit, chainId); @@ -120,8 +139,8 @@ async function getSignedTxs(wallet, greeterContracts, gasPrice, gasLimit, chainI walletData['index'] = i; walletData['address'] = wallet.address; walletData['privateKey'] = wallet.privateKey; - walletData['latestBalance'] = ethers.utils.formatEther(balance); - walletData['latestNonce'] = await walletProvider.getTransactionCount(); + walletData['latestBalance'] = formatEther(balance); + walletData['latestNonce'] = await walletProvider.getNonce(); walletData['signedTxs'] = signedTxCollection; wallets.push(walletData); } diff --git a/k6/src/scenarios/apis.js b/k6/src/scenarios/apis.js index 4f3ff7d795..f2f953d8b7 100644 --- a/k6/src/scenarios/apis.js +++ b/k6/src/scenarios/apis.js @@ -23,7 +23,7 @@ import { textSummary } from 'https://jslib.k6.io/k6-summary/0.0.1/index.js'; import { markdownReport } from '../lib/common.js'; import { funcs, options, scenarioDurationGauge } from './test/index.js'; -import { setupTestParameters } from './test/bootstrapEnvParameters.js'; +import { setupTestParameters } from '../lib/bootstrapEnvParameters.js'; function handleSummary(data) { return { diff --git a/k6/src/scenarios/test-ws/common.js b/k6/src/scenarios/test-ws/common.js new file mode 100644 index 0000000000..19c4e9add3 --- /dev/null +++ b/k6/src/scenarios/test-ws/common.js @@ -0,0 +1,95 @@ +/*- + * + * Hedera JSON RPC Relay + * + * Copyright (C) 2022-2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import ws from 'k6/ws'; +import { check } from 'k6'; + +const errorField = 'error'; +const resultField = 'result'; + +const isDebugMode = __ENV['DEBUG_MODE'] === 'true'; + +let requestId = 1; + +function getPayLoad(methodName, paramInput = []) { + return JSON.stringify({ + id: requestId++, + jsonrpc: '2.0', + method: methodName, + params: paramInput, + }); +} + +function connectToWebSocket(url, methodName, params = [], responseChecks = {}) { + return ws.connect(url, {}, (socket) => { + socket.on('open', () => { + const message = getPayLoad(methodName, params); + if (isDebugMode) { + console.log('Connected, sending request: ' + message); + } + socket.send(message); + + socket.on('message', (message) => { + check(message, responseChecks); + socket.close(); + }); + }); + + socket.on('close', function () { + if (isDebugMode) { + console.log('Disconnected'); + } + }); + + socket.on('error', (e) => { + if (isDebugMode) { + console.error('Received WebSocketError:', e); + } + }); + }); +} + +function isNonErrorResponse(message) { + try { + const response = JSON.parse(message); + const success = response.hasOwnProperty(resultField) && !response.hasOwnProperty(errorField); + if (isDebugMode) { + console.log(`isNonErrorResponse: message=${message}, result=${success}`); + } + return success; + } catch (e) { + return false; + } +} + +function isErrorResponse(message) { + try { + const response = JSON.parse(message); + const success = response.hasOwnProperty(errorField) && !response.hasOwnProperty(resultField); + if (isDebugMode) { + console.log(`isErrorResponse: message=${message}, result=${success}`); + } + return success; + } catch (e) { + return false; + } +} + +export { connectToWebSocket, isNonErrorResponse, isErrorResponse }; diff --git a/k6/src/scenarios/test-ws/eth_chainId.js b/k6/src/scenarios/test-ws/eth_chainId.js new file mode 100644 index 0000000000..73343f465c --- /dev/null +++ b/k6/src/scenarios/test-ws/eth_chainId.js @@ -0,0 +1,37 @@ +/*- + * + * Hedera JSON RPC Relay + * + * Copyright (C) 2022-2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { TestScenarioBuilder } from '../../lib/common.js'; +import { connectToWebSocket, isNonErrorResponse } from './common.js'; + +const url = __ENV.WS_RELAY_BASE_URL; +const methodName = 'eth_chainId'; + +const { options, run } = new TestScenarioBuilder() + .name(methodName) // use unique scenario name among all tests + .request(() => connectToWebSocket( + url, + methodName, + [], + { methodName: (r) => isNonErrorResponse(r) } + )) + .build(); + +export { options, run }; diff --git a/k6/src/scenarios/test-ws/eth_subscribe_logs.js b/k6/src/scenarios/test-ws/eth_subscribe_logs.js new file mode 100644 index 0000000000..feb95a1e72 --- /dev/null +++ b/k6/src/scenarios/test-ws/eth_subscribe_logs.js @@ -0,0 +1,43 @@ +/*- + * + * Hedera JSON RPC Relay + * + * Copyright (C) 2022-2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { setupTestParameters } from '../../lib/bootstrapEnvParameters.js'; +import { TestScenarioBuilder } from '../../lib/common.js'; +import { subscribeEvents } from '../../lib/constants.js'; +import { connectToWebSocket, isNonErrorResponse } from './common.js'; + +const url = __ENV.WS_RELAY_BASE_URL; +const methodName = 'eth_subscribe'; + +const { options, run } = new TestScenarioBuilder() + .name(methodName + '_logs') // use unique scenario name among all tests + .request((testParameters) => { + return connectToWebSocket( + url, + methodName, + [subscribeEvents.logs, { address: testParameters.contractsAddresses[0] }], + { methodName: (r) => isNonErrorResponse(r) } + ); + }) + .build(); + +export { options, run }; + +export const setup = setupTestParameters; diff --git a/k6/src/scenarios/test-ws/eth_subscribe_newHeads.js b/k6/src/scenarios/test-ws/eth_subscribe_newHeads.js new file mode 100644 index 0000000000..534ba5a52f --- /dev/null +++ b/k6/src/scenarios/test-ws/eth_subscribe_newHeads.js @@ -0,0 +1,38 @@ +/*- + * + * Hedera JSON RPC Relay + * + * Copyright (C) 2022-2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { TestScenarioBuilder } from '../../lib/common.js'; +import { subscribeEvents } from '../../lib/constants.js'; +import { connectToWebSocket, isNonErrorResponse } from './common.js'; + +const url = __ENV.WS_RELAY_BASE_URL; +const methodName = 'eth_subscribe'; + +const { options, run } = new TestScenarioBuilder() + .name(methodName + '_newHeads') // use unique scenario name among all tests + .request(() => connectToWebSocket( + url, + methodName, + [subscribeEvents.newHeads], + { methodName: (r) => isNonErrorResponse(r) } + )) + .build(); + +export { options, run }; diff --git a/k6/src/scenarios/test-ws/eth_subscribe_newPendingTransactions.js b/k6/src/scenarios/test-ws/eth_subscribe_newPendingTransactions.js new file mode 100644 index 0000000000..91f426b7ae --- /dev/null +++ b/k6/src/scenarios/test-ws/eth_subscribe_newPendingTransactions.js @@ -0,0 +1,38 @@ +/*- + * + * Hedera JSON RPC Relay + * + * Copyright (C) 2022-2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { TestScenarioBuilder } from '../../lib/common.js'; +import { subscribeEvents } from '../../lib/constants.js'; +import { connectToWebSocket, isErrorResponse } from './common.js'; + +const url = __ENV.WS_RELAY_BASE_URL; +const methodName = 'eth_subscribe'; + +const { options, run } = new TestScenarioBuilder() + .name(methodName + '_newPendingTransactions') // use unique scenario name among all tests + .request(() => connectToWebSocket( + url, + methodName, + [subscribeEvents.newPendingTransactions], + { methodName: (r) => isErrorResponse(r) } + )) + .build(); + +export { options, run }; diff --git a/k6/src/scenarios/test-ws/index.js b/k6/src/scenarios/test-ws/index.js new file mode 100644 index 0000000000..b101e7a91c --- /dev/null +++ b/k6/src/scenarios/test-ws/index.js @@ -0,0 +1,39 @@ +/*- + * + * Hedera JSON RPC Relay + * + * Copyright (C) 2022-2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { getSequentialTestScenarios } from '../../lib/common.js'; + +// import test modules +import * as eth_chainId from './eth_chainId.js'; +import * as eth_subscribe_logs from './eth_subscribe_logs.js'; +import * as eth_subscribe_newHeads from './eth_subscribe_newHeads.js'; +import * as eth_subscribe_newPendingTransactions from './eth_subscribe_newPendingTransactions.js'; + +// add test modules here +const tests = { + eth_chainId, + eth_subscribe_logs, + eth_subscribe_newHeads, + eth_subscribe_newPendingTransactions, +}; + +const { funcs, options, scenarioDurationGauge } = getSequentialTestScenarios(tests); + +export { funcs, options, scenarioDurationGauge }; diff --git a/k6/src/scenarios/test/eth_getBalance.js b/k6/src/scenarios/test/eth_getBalance.js index 2e6d452912..07c2680f8c 100644 --- a/k6/src/scenarios/test/eth_getBalance.js +++ b/k6/src/scenarios/test/eth_getBalance.js @@ -23,7 +23,7 @@ import { randomIntBetween } from 'https://jslib.k6.io/k6-utils/1.4.0/index.js'; import { TestScenarioBuilder } from '../../lib/common.js'; import { isNonErrorResponse, httpParams, getPayLoad } from './common.js'; -import { setupTestParameters } from './bootstrapEnvParameters.js'; +import { setupTestParameters } from '../../lib/bootstrapEnvParameters.js'; const methodName = 'eth_getBalance'; const { options, run } = new TestScenarioBuilder() diff --git a/k6/src/scenarios/test/eth_getBlockByHash.js b/k6/src/scenarios/test/eth_getBlockByHash.js index 13a6ac8d62..473dab3d5f 100644 --- a/k6/src/scenarios/test/eth_getBlockByHash.js +++ b/k6/src/scenarios/test/eth_getBlockByHash.js @@ -22,7 +22,7 @@ import http from 'k6/http'; import { TestScenarioBuilder } from '../../lib/common.js'; import { isNonErrorResponse, httpParams, getPayLoad } from './common.js'; -import { setupTestParameters } from './bootstrapEnvParameters.js'; +import { setupTestParameters } from '../../lib/bootstrapEnvParameters.js'; const methodName = 'eth_getBlockByHash'; const { options, run } = new TestScenarioBuilder() diff --git a/k6/src/scenarios/test/eth_getBlockTransactionCountByHash.js b/k6/src/scenarios/test/eth_getBlockTransactionCountByHash.js index 9ae97002cc..258ff9a2bc 100644 --- a/k6/src/scenarios/test/eth_getBlockTransactionCountByHash.js +++ b/k6/src/scenarios/test/eth_getBlockTransactionCountByHash.js @@ -22,7 +22,7 @@ import http from 'k6/http'; import { TestScenarioBuilder } from '../../lib/common.js'; import { isNonErrorResponse, httpParams, getPayLoad } from './common.js'; -import { setupTestParameters } from './bootstrapEnvParameters.js'; +import { setupTestParameters } from '../../lib/bootstrapEnvParameters.js'; const methodName = 'eth_getBlockTransactionCountByHash'; const { options, run } = new TestScenarioBuilder() diff --git a/k6/src/scenarios/test/eth_getCode.js b/k6/src/scenarios/test/eth_getCode.js index 722506764e..5926cd35cd 100644 --- a/k6/src/scenarios/test/eth_getCode.js +++ b/k6/src/scenarios/test/eth_getCode.js @@ -23,7 +23,7 @@ import { randomIntBetween } from 'https://jslib.k6.io/k6-utils/1.4.0/index.js'; import { TestScenarioBuilder } from '../../lib/common.js'; import { isNonErrorResponse, httpParams, getPayLoad } from './common.js'; -import { setupTestParameters } from './bootstrapEnvParameters.js'; +import { setupTestParameters } from '../../lib/bootstrapEnvParameters.js'; const methodName = 'eth_getCode'; const { options, run } = new TestScenarioBuilder() diff --git a/k6/src/scenarios/test/eth_getStorageAt.js b/k6/src/scenarios/test/eth_getStorageAt.js index c9e400616f..5ecb2af151 100644 --- a/k6/src/scenarios/test/eth_getStorageAt.js +++ b/k6/src/scenarios/test/eth_getStorageAt.js @@ -22,7 +22,7 @@ import http from 'k6/http'; import { TestScenarioBuilder } from '../../lib/common.js'; import { httpParams, getPayLoad, isNonErrorResponse } from './common.js'; -import { setupTestParameters } from './bootstrapEnvParameters.js'; +import { setupTestParameters } from '../../lib/bootstrapEnvParameters.js'; const methodName = 'eth_getStorageAt'; const { options, run } = new TestScenarioBuilder() diff --git a/k6/src/scenarios/test/eth_getTransactionByBlockHashAndIndex.js b/k6/src/scenarios/test/eth_getTransactionByBlockHashAndIndex.js index f3b86865db..5e7ae04943 100644 --- a/k6/src/scenarios/test/eth_getTransactionByBlockHashAndIndex.js +++ b/k6/src/scenarios/test/eth_getTransactionByBlockHashAndIndex.js @@ -22,7 +22,7 @@ import http from 'k6/http'; import { TestScenarioBuilder } from '../../lib/common.js'; import { isNonErrorResponse, httpParams, getPayLoad } from './common.js'; -import { setupTestParameters } from './bootstrapEnvParameters.js'; +import { setupTestParameters } from '../../lib/bootstrapEnvParameters.js'; const methodName = 'eth_getTransactionByBlockHashAndIndex'; const { options, run } = new TestScenarioBuilder() diff --git a/k6/src/scenarios/test/eth_getTransactionByHash.js b/k6/src/scenarios/test/eth_getTransactionByHash.js index add58a1eba..5818a2ad7b 100644 --- a/k6/src/scenarios/test/eth_getTransactionByHash.js +++ b/k6/src/scenarios/test/eth_getTransactionByHash.js @@ -22,7 +22,7 @@ import http from 'k6/http'; import { TestScenarioBuilder } from '../../lib/common.js'; import { isNonErrorResponse, httpParams, getPayLoad } from './common.js'; -import { setupTestParameters } from './bootstrapEnvParameters.js'; +import { setupTestParameters } from '../../lib/bootstrapEnvParameters.js'; const methodName = 'eth_getTransactionByHash'; const { options, run } = new TestScenarioBuilder() diff --git a/k6/src/scenarios/test/eth_getTransactionCount.js b/k6/src/scenarios/test/eth_getTransactionCount.js index 3901296e8a..d56e62e8a6 100644 --- a/k6/src/scenarios/test/eth_getTransactionCount.js +++ b/k6/src/scenarios/test/eth_getTransactionCount.js @@ -23,7 +23,7 @@ import { randomIntBetween } from 'https://jslib.k6.io/k6-utils/1.1.0/index.js'; import { TestScenarioBuilder } from '../../lib/common.js'; import { isNonErrorResponse, httpParams, getPayLoad } from './common.js'; -import { setupTestParameters } from './bootstrapEnvParameters.js'; +import { setupTestParameters } from '../../lib/bootstrapEnvParameters.js'; const methodName = 'eth_getTransactionCount'; const { options, run } = new TestScenarioBuilder() diff --git a/k6/src/scenarios/test/eth_getTransactionReceipt.js b/k6/src/scenarios/test/eth_getTransactionReceipt.js index c8ff61ce5d..dc2f2088f2 100644 --- a/k6/src/scenarios/test/eth_getTransactionReceipt.js +++ b/k6/src/scenarios/test/eth_getTransactionReceipt.js @@ -22,7 +22,7 @@ import http from 'k6/http'; import { TestScenarioBuilder } from '../../lib/common.js'; import { isNonErrorResponse, httpParams, getPayLoad } from './common.js'; -import { setupTestParameters } from './bootstrapEnvParameters.js'; +import { setupTestParameters } from '../../lib/bootstrapEnvParameters.js'; const methodName = 'eth_getTransactionReceipt'; const { options, run } = new TestScenarioBuilder() diff --git a/k6/src/scenarios/ws-apis.js b/k6/src/scenarios/ws-apis.js new file mode 100644 index 0000000000..b2a4e1d736 --- /dev/null +++ b/k6/src/scenarios/ws-apis.js @@ -0,0 +1,43 @@ +/*- + * + * Hedera JSON RPC Relay + * + * Copyright (C) 2022-2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import exec from 'k6/execution'; +import { textSummary } from 'https://jslib.k6.io/k6-summary/0.0.1/index.js'; + +import { markdownReport } from '../lib/common.js'; +import { setupTestParameters } from '../lib/bootstrapEnvParameters.js'; +import { funcs, options, scenarioDurationGauge } from './test-ws/index.js'; + +function handleSummary(data) { + return { + stdout: textSummary(data, { indent: ' ', enableColors: true }), + 'report.md': markdownReport(data, false, options.scenarios), + }; +} + +function run(testParameters) { + const scenario = exec.scenario; + funcs[scenario.name](testParameters, scenario.iterationInTest, exec.vu.idInInstance - 1, exec.vu.iterationInScenario); + scenarioDurationGauge.add(Date.now() - scenario.startTime, { scenario: scenario.name }); +} + +export { handleSummary, options, run }; + +export const setup = setupTestParameters;