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

fix: A series of small changes to stabilize tests #3242

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
6 changes: 5 additions & 1 deletion packages/server/tests/helpers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,13 +256,17 @@ export class Utils {
requestId: any,
mirrorNodeServer: any,
) => {
const gasPriceDeviation = parseFloat(ConfigService.get('TEST_GAS_PRICE_DEVIATION') ?? '0.2');
const gasPrice = await rpcServer.gasPrice(requestId);
const gasPriceWithDeviation = gasPrice * (1 + gasPriceDeviation);

const transaction = {
value: ONE_TINYBAR,
gasLimit: numberTo0x(30000),
chainId: Number(CHAIN_ID),
to: accounts[1].address,
nonce: await rpcServer.getAccountNonce(accounts[0].address, requestId),
maxFeePerGas: await rpcServer.gasPrice(requestId),
maxFeePerGas: gasPriceWithDeviation,
};

const signedTx = await accounts[0].wallet.signTransaction(transaction);
Expand Down
1 change: 1 addition & 0 deletions packages/server/tests/localAcceptance.env
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ HBAR_RATE_LIMIT_TINYBAR=9000000000# 90 HBARs
HBAR_RATE_LIMIT_DURATION=86400000# 24 hours
HBAR_RATE_LIMIT_BASIC=6000000000# 60 HBARs
HBAR_SPENDING_PLANS_CONFIG_FILE=./packages/server/tests/testSpendingPlansConfig.json
SUBSCRIPTIONS_ENABLED=true
2 changes: 1 addition & 1 deletion packages/ws-server/tests/acceptance/call.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ describe('@web-socket-batch-1 eth_call', async function () {
});

afterEach(async () => {
if (ethersWsProvider) await ethersWsProvider.destroy();
ethersWsProvider = await WsTestHelper.closeWebsocketConnections(ethersWsProvider);
});

after(async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ describe('@web-socket-batch-1 eth_getBlockByNumber', async function () {
});

afterEach(async () => {
if (ethersWsProvider) await ethersWsProvider.destroy();
ethersWsProvider = await WsTestHelper.closeWebsocketConnections(ethersWsProvider);
});

after(async () => {
Expand All @@ -63,8 +63,10 @@ describe('@web-socket-batch-1 eth_getBlockByNumber', async function () {

it(`@release Should execute eth_getBlockByNumber on Standard Web Socket and handle valid requests correctly`, async () => {
const expectedResult = await global.relay.call(METHOD_NAME, ['latest', false]);
const response = await WsTestHelper.sendRequestToStandardWebSocket(METHOD_NAME, [expectedResult.number, true]);
await Utils.wait(1000);
const response = await WsTestHelper.sendRequestToStandardWebSocketWithResolve(METHOD_NAME, [
expectedResult.number,
true,
]);
WsTestHelper.assertJsonRpcObject(response);
expect(response.result).to.deep.eq(expectedResult);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ describe('@web-socket-batch-2 eth_getTransactionReceipt', async function () {
});

afterEach(async () => {
if (ethersWsProvider) await ethersWsProvider.destroy();
ethersWsProvider = await WsTestHelper.closeWebsocketConnections(ethersWsProvider);
});

after(async () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/ws-server/tests/acceptance/newFilter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ describe('@web-socket-batch-2 eth_newFilter', async function () {
}

it(`@release Should execute eth_newFilter on Standard Web Socket and handle valid requests correctly`, async () => {
const response = await WsTestHelper.sendRequestToStandardWebSocket(METHOD_NAME, [wsFilterObj]);
const response = await WsTestHelper.sendRequestToStandardWebSocketWithResolve(METHOD_NAME, [wsFilterObj]);
WsTestHelper.assertJsonRpcObject(response);
const filterId = response.result;

Expand Down
31 changes: 20 additions & 11 deletions packages/ws-server/tests/acceptance/subscribe.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const unsubscribeAndCloseConnections = async (provider: ethers.WebSocketProvider
return result;
};

const createLogs = async (contract: ethers.Contract, requestId) => {
const createLogs = async (wsProvider: ethers.WebSocketProvider, contract: ethers.Contract, requestId) => {
const gasOptions = await Utils.gasOptions(requestId);

const tx1 = await contract.log0(10, gasOptions);
Expand All @@ -68,9 +68,22 @@ const createLogs = async (contract: ethers.Contract, requestId) => {
const tx5 = await contract.log4(11, 22, 33, 44, gasOptions);
await tx5.wait();

await new Promise((resolve) => setTimeout(resolve, 2000));
fetchTransactionWithRetry(wsProvider, tx5.hash);
};

async function fetchTransactionWithRetry(txHash, maxRetries = 5, delay = 1000) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
const transaction = await WsTestHelper.sendRequestToStandardWebSocket('eth_getTransactionByHash', [txHash]);
if (transaction && transaction.result.blockNumber) {
// Transaction is fully populated
return transaction;
}
// Wait for a specified delay before retrying
await new Promise((resolve) => setTimeout(resolve, delay));
}
throw new Error(`Transaction ${txHash} not fully populated after ${maxRetries} attempts.`);
}

describe('@web-socket-batch-3 eth_subscribe', async function () {
this.timeout(240 * 1000); // 240 seconds
const CHAIN_ID = ConfigService.get('CHAIN_ID') || 0;
Expand Down Expand Up @@ -123,11 +136,7 @@ describe('@web-socket-batch-3 eth_subscribe', async function () {
});

afterEach(async () => {
if (wsProvider) {
await wsProvider.destroy();
await new Promise((resolve) => setTimeout(resolve, 1000));
}
if (server) expect(server._connections).to.equal(0);
wsProvider = await WsTestHelper.closeWebsocketConnections(wsProvider);
});

describe('Connection', async function () {
Expand Down Expand Up @@ -561,7 +570,7 @@ describe('@web-socket-batch-3 eth_subscribe', async function () {
describe('Subscribes to log events', async function () {
let logContractSigner2, logContractSigner3, wsLogsProvider, contracts, cLen;
let ANONYMOUS_LOG_DATA, topic1, topic2;
let eventsReceivedGlobal: any[] = [];
const eventsReceivedGlobal: any[] = [];

// Deploy several contracts
before(async function () {
Expand All @@ -573,7 +582,7 @@ describe('@web-socket-batch-3 eth_subscribe', async function () {
logContractSigner2 = await Utils.deployContractWithEthersV2([], LogContractJson, accounts[0].wallet);
logContractSigner3 = await Utils.deployContractWithEthersV2([], LogContractJson, accounts[0].wallet);

await createLogs(logContractSigner2, requestId);
await createLogs(wsLogsProvider, logContractSigner2, requestId);
const mirrorLogs = await mirrorNode.get(`/contracts/${logContractSigner2.target}/results/logs`, requestId);

expect(mirrorLogs).to.exist;
Expand Down Expand Up @@ -633,7 +642,7 @@ describe('@web-socket-batch-3 eth_subscribe', async function () {

// Create logs from all deployed contracts
for (let i = 0; i < cLen; i++) {
await createLogs(contracts[i], requestId);
await createLogs(wsLogsProvider, contracts[i], requestId);
}

await wsLogsProvider.websocket.close();
Expand All @@ -652,7 +661,7 @@ describe('@web-socket-batch-3 eth_subscribe', async function () {
});

it('@release Subscribes for contract logs for a specific contract address (using evmAddress)', async function () {
let eventsReceived = eventsReceivedGlobal[1];
const eventsReceived = eventsReceivedGlobal[1];

// Only the logs from logContractSigner.target are captured
expect(eventsReceived.length).to.eq(5);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,7 @@ describe('@web-socket-batch-3 eth_subscribe newHeads', async function () {
});

afterEach(async () => {
if (wsProvider) {
await wsProvider.destroy();
await new Promise((resolve) => setTimeout(resolve, 1000));
}
wsProvider = await WsTestHelper.closeWebsocketConnections(wsProvider);
});

describe('Configuration', async function () {
Expand Down
4 changes: 2 additions & 2 deletions packages/ws-server/tests/acceptance/validations.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ describe('@release @web-socket-batch-1 JSON-RPC requests validation', async func

WsTestHelper.overrideEnvsInMochaDescribe({ REQUEST_ID_IS_OPTIONAL: true });

let ethersWsProvider: WebSocketProvider;
let ethersWsProvider: WebSocketProvider | null;

beforeEach(async () => {
ethersWsProvider = new ethers.WebSocketProvider(WsTestConstant.WS_RELAY_URL);
});

afterEach(async () => {
if (ethersWsProvider) await ethersWsProvider.destroy();
ethersWsProvider = await WsTestHelper.closeWebsocketConnections(ethersWsProvider);
});

after(async () => {
Expand Down
73 changes: 72 additions & 1 deletion packages/ws-server/tests/helper/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

import WebSocket from 'ws';
import { expect } from 'chai';
import { WebSocketProvider } from 'ethers';
import { ethers, WebSocketProvider } from 'ethers';
import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services';
import { ConfigServiceTestHelper } from '../../../config-service/tests/configServiceTestHelper';

Expand Down Expand Up @@ -68,6 +68,52 @@ export class WsTestHelper {
return response;
}

static sendRequestToStandardWebSocketWithResolve(method: string, params: any, timeout = 5000): Promise<any> {
return new Promise((resolve, reject) => {
const BATCH_REQUEST_METHOD_NAME = 'batch_request';
const webSocket = new WebSocket(WsTestConstant.WS_RELAY_URL);
let isResolved = false;

const timer = setTimeout(() => {
if (!isResolved) {
webSocket.close();
reject(new Error('WebSocket response timeout'));
}
}, timeout);

webSocket.on('error', (error) => {
if (!isResolved) {
isResolved = true;
clearTimeout(timer);
webSocket.close();
reject(error);
}
});

webSocket.on('open', () => {
let request;

if (method === BATCH_REQUEST_METHOD_NAME) {
request = JSON.stringify(params);
} else {
request = JSON.stringify(WsTestHelper.prepareJsonRpcObject(method, params));
}

webSocket.send(request);
});

webSocket.on('message', (data: string) => {
if (!isResolved) {
isResolved = true;
clearTimeout(timer);
const response = JSON.parse(data);
webSocket.close();
resolve(response);
}
});
});
}

static async assertFailInvalidParamsStandardWebSocket(method: string, params: any[]) {
const response = await WsTestHelper.sendRequestToStandardWebSocket(method, params);
WsTestHelper.assertJsonRpcObject(response);
Expand Down Expand Up @@ -162,6 +208,31 @@ export class WsTestHelper {
tests();
});
}

static async closeWebsocketConnections(ethersWsProvider: ethers.WebSocketProvider | null) {
if (ethersWsProvider) {
const ws = ethersWsProvider._websocket;
if (ws) {
if (ws.readyState === WebSocket.CONNECTING) {
// Wait for the WebSocket to either open or close
await new Promise((resolve) => {
const handleOpenOrClose = () => {
ws.removeEventListener('open', handleOpenOrClose);
ws.removeEventListener('close', handleOpenOrClose);
resolve();
};
ws.addEventListener('open', handleOpenOrClose);
ws.addEventListener('close', handleOpenOrClose);
});
}
// Now it's safe to destroy the provider
await ethersWsProvider.destroy();
}
ethersWsProvider = null;
await new Promise((resolve) => setTimeout(resolve, 1000));
}
return ethersWsProvider;
}
}

export class WsTestConstant {
Expand Down
Loading