Skip to content

Commit

Permalink
tests: long running eth node tests for each client (#588)
Browse files Browse the repository at this point in the history
* tests: long running eth node tests for each client

* fix: prysm p2p flags. erigon data dir set
  • Loading branch information
jgresham authored May 31, 2024
1 parent 999d26e commit 6476779
Show file tree
Hide file tree
Showing 11 changed files with 619 additions and 9 deletions.
45 changes: 45 additions & 0 deletions .github/workflows/eth-nodes-sync-test-ubuntu.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: eth-nodes-sync-tests-ubuntu

on:
# pull_request:
# branches:
# - main
workflow_dispatch:

jobs:
e2e-build-n-test:
environment: staging
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-24.04]
node-version: [20.x]

steps:
- uses: actions/checkout@v4
- name: 💚 Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

- name: 🧱 Install Dependencies
run: |
sudo apt-get update
sudo apt-get install --no-install-recommends -y podman
npm ci
- name: 📦 Bundle Application
env:
DEBUG: "*electron*"
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
MP_PROJECT_TOKEN: ${{ secrets.MP_PROJECT_TOKEN }}
MP_PROJECT_ENV: ${{ vars.MP_PROJECT_ENV }}
NICENODE_ENV: ${{ vars.NICENODE_ENV }}
NO_CODE_SIGNING: true
run: |
npm run package -- --arch=x64
- name: 🧪 Run Tests
uses: coactions/setup-xvfb@6b00cf1889f4e1d5a48635647013c0508128ee1a
with:
run: npm run e2eEthNodeSpecs
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"wdio": "cross-env TEST_ENV=wdio NODE_ENV=test wdio run ./wdio.conf.ts",
"e2eEthNodeSpecs": "cross-env TEST_ENV=wdio NODE_ENV=test wdio run ./wdioEthNodeSpecs.conf.ts",
"docs:nodeSpec": "typedoc --plugin typedoc-plugin-markdown --name \"Node Spec examples\" --readme src/common/index.md --entryDocument index.md --out docs src/common/*"
},
"devDependencies": {
Expand Down
4 changes: 2 additions & 2 deletions src/common/NodeSpecs/erigon/erigon-v1.0.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@
]
},
"docker": {
"containerVolumePath": "/root/.ethereum",
"containerVolumePath": "/root/.local/share/erigon",
"raw": "",
"forcedRawNodeInput": "--authrpc.addr 0.0.0.0 --authrpc.jwtsecret /root/.ethereum/jwtsecret"
"forcedRawNodeInput": "--authrpc.addr 0.0.0.0 --datadir /root/.local/share/erigon --authrpc.jwtsecret /root/.local/share/erigon/jwtsecret"
}
}
},
Expand Down
4 changes: 2 additions & 2 deletions src/common/NodeSpecs/prysm/prysm-v1.0.0.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
},
"p2pPortsTcp": {
"displayName": "P2P listening port (TCP)",
"cliConfigPrefix": "--tcp-port=",
"cliConfigPrefix": "--p2p-tcp-port=",
"uiControl": {
"type": "text"
},
Expand All @@ -96,7 +96,7 @@
},
"p2pPortsUdp": {
"displayName": "P2P discovery port (UDP)",
"cliConfigPrefix": "--udp-port=",
"cliConfigPrefix": "--p2p-udp-port=",
"uiControl": {
"type": "text"
},
Expand Down
2 changes: 2 additions & 0 deletions src/renderer/Generics/redesign/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ export const Header = ({ nodeOverview, isPodmanRunning }: HeaderProps) => {
}}
>
<Button
id="nodeSettingsBtn"
iconId="settings"
variant="icon"
size="small"
Expand Down Expand Up @@ -212,6 +213,7 @@ export const Header = ({ nodeOverview, isPodmanRunning }: HeaderProps) => {
)}
{screenType === 'nodePackage' && (
<MenuItem
id="removeNodeMenuItem"
text={g('RemoveNode')}
onClick={() => {
dispatch(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { type MetricStats, MetricTypes } from '../MetricTypes/MetricTypes';
import { type MetricStats, MetricTypes } from '../MetricTypes/MetricTypes.js';
import VerticalLine from '../VerticalLine/VerticalLine';
import type { NodeOverviewProps } from '../consts';
import { getSyncStatus } from '../utils';
Expand Down
4 changes: 3 additions & 1 deletion src/renderer/Generics/redesign/MetricTypes/MetricTypes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,9 @@ export const MetricTypes = ({
<div className={iconContainer}>{iconComponent}</div>
<div className={textContainer}>
<div className={titleContainer}>
<div className={titleStyle}>{titleText}</div>
<div id={`${statsType}Value`} className={titleStyle}>
{titleText}
</div>
<div className={labelStyle}>{labelText}</div>
</div>
<div className={infoStyle}>{info}</div>
Expand Down
File renamed without changes.
225 changes: 225 additions & 0 deletions test/specs/longRunningEthNodes.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
import os from 'node:os';
/* global $ */
import { expect } from '@wdio/globals';
import { browser } from 'wdio-electron-service';
// import { removeAllNodePackages } from '../../src/main/nodePackageManager.js';
import { afterAll } from 'vitest';


// const cleanup = async () => {
// // remove all nodes and delete their data
// await removeAllNodePackages();
// }
const addNode = async () => {
describe('BESU & LIGTHOUSE: Should pass all of the eth node successfully starts syncing tests:', async () => {
it('Add Ethereum Node with specific clients', async () => {
await expect(await $('span*=Add Node')).toBeDisplayed();
await $('span*=Add Node').click();
await expect(await $('span*=Continue')).toBeDisplayed();
await $('span*=Continue').click();
// await expect(await $('div*=Nethermind')).toBeDisplayed();
await $('div*=Nethermind').click();
await $('div*=Besu').click();

await $('div*=Lodestar').click();
await $('div*=Lighthouse').click();

await $('span*=Continue').click();
await $('span*=Start node').click();
// after docker containers are downloaded and the node is started, the node should be online
// await expect(await $('div*=Online')).toBeDisplayed();
}).timeout(120000); // wait 3 minutes for the node to download & start
});

await testsForEachNode();

describe('GETH & TEKU: Should pass all of the eth node successfully starts syncing tests:', async () => {
it('Add Ethereum Node with specific clients', async () => {
await expect(await $('span*=Add Node')).toBeDisplayed();
await $('span*=Add Node').click();
await expect(await $('span*=Continue')).toBeDisplayed();
await $('span*=Continue').click();
// await expect(await $('div*=Nethermind')).toBeDisplayed();
await $('div*=Nethermind').click();
await $('div*=Geth').click();

await $('div*=Lodestar').click();
await $('div*=Teku').click();

await $('span*=Continue').click();
await $('span*=Start node').click();
// after docker containers are downloaded and the node is started, the node should be online
// await expect(await $('div*=Online')).toBeDisplayed();
}).timeout(120000); // wait 3 minutes for the node to download & start
});

await testsForEachNode();

describe('RETH & PRYSM: Should pass all of the eth node successfully starts syncing tests:', async () => {
it('Add Ethereum Node with specific clients', async () => {
await expect(await $('span*=Add Node')).toBeDisplayed();
await $('span*=Add Node').click();
await expect(await $('span*=Continue')).toBeDisplayed();
await $('span*=Continue').click();
// await expect(await $('div*=Nethermind')).toBeDisplayed();
await $('div*=Nethermind').click();
await $('div*=Reth').click();

await $('div*=Lodestar').click();
await $('div*=Prysm').click();

await $('span*=Continue').click();
await $('span*=Start node').click();
// after docker containers are downloaded and the node is started, the node should be online
// await expect(await $('div*=Online')).toBeDisplayed();
}).timeout(120000); // wait 3 minutes for the node to download & start
});

await testsForEachNode();

describe('Erigon & Nimbus: Should pass all of the eth node successfully starts syncing tests:', async () => {
it('Add Ethereum Node with specific clients', async () => {
await expect(await $('span*=Add Node')).toBeDisplayed();
await $('span*=Add Node').click();
await expect(await $('span*=Continue')).toBeDisplayed();
await $('span*=Continue').click();
// await expect(await $('div*=Nethermind')).toBeDisplayed();
await $('div*=Nethermind').click();
await $('div*=Erigon').click();

await $('div*=Lodestar').click();
await $('div*=Nimbus').click();

await $('span*=Continue').click();
await $('span*=Start node').click();
// after docker containers are downloaded and the node is started, the node should be online
// await expect(await $('div*=Online')).toBeDisplayed();
}).timeout(120000); // wait 3 minutes for the node to download & start
});

await testsForEachNode();
}

const testsForEachNode = async () => {
describe('Should pass all of the eth node successfully starts syncing tests:', async () => {

it('Ethereum Node screen should be displayed with syncing and stop btn', async () => {
await expect(await $('div*=Ethereum Node')).toBeDisplayed();
await expect(await $('div*=Syncing')).toBeDisplayed();
await expect(await $('span*=Stop')).toBeDisplayed();
// after docker containers are downloaded and the node is started, the node should be online
// await expect(await $('div*=Online')).toBeDisplayed();
}).timeout(120000); // wait 3 minutes for the node to download & start

it('Ethereum Node should have all hardware statistic usage > 0', async () => {
// wait 20 seconds for stats to be set
const memUsageElement = await $('#memoryUsagePercentValue');
const cpuLoadElement = await $('#cpuLoadValue');
const diskUsageElement = await $('#diskUsageGBsValue');
await browser.waitUntil(async () => Number.parseFloat(await memUsageElement.getText()) > 1, {timeout: 40000, interval: 5000});
await browser.waitUntil(async () => Number.parseFloat(await cpuLoadElement.getText()) > 1, {timeout: 40000, interval: 5000});
await browser.waitUntil(async () => {
console.log("Waiting for disk usage to be > 1 GB...")
return Number.parseFloat(await diskUsageElement.getText()) > 0.1 // todo: revert to 1
}, { timeout: 5*60*1000, interval: 15000 }); // give 5 minutes to download 1 GB
}).timeout(10*60*1000); // 10 minutes

it('clicking stop node btn should stop the node and show resume button', async () => {
const stopBtn = (await $('span*=Stop')).parentElement();
(await stopBtn).click();
// can take an execution node ~30 seconds to fully stop
await browser.pause(25000);
// await expect(await $('div*=Stopping')).toBeDisplayed();
// ...
await expect(await $('div*=Stopped')).toBeDisplayed();
await expect(await $('span*=Resume')).toBeDisplayed();
}).timeout(120000); // wait 3 minutes for the node to download & start

it('clicking node package settings and remove node should show no active nodes', async () => {
await $('#nodeSettingsBtn').click();
const removeNodeBtn = (await $('div*=Remove Node')).parentElement();
(await removeNodeBtn).click();
// await $('#removeNodeMenuItem').click();
const confirmRemoveNodeBtn = (await $('span*=Remove node')).parentElement();
(await confirmRemoveNodeBtn).click();

// No active nodes if there are no nodes... next click "Add Node" btn
await expect(await $('div*=No active nodes')).toBeDisplayed();

// await browser.pause(2000);
// after docker containers are downloaded and the node is started, the node should be online
// await expect(await $('div*=Online')).toBeDisplayed();
// await expect(await $('div*=')).toBeDisplayed();
}).timeout(120000); // wait 3 minutes for the node to download & start
});

// afterAll(async () => {
// await cleanup();
// });
}

describe('Splash screen tests', async () => {
it('application should open to splash screen with welcome message', async () => {
const elWelcome = await $('#welcome');
await expect(elWelcome).toBeDisplayed();
await expect(elWelcome).toHaveText(expect.stringContaining('NiceNode'));
});

it('clicking get started btn should take the user to add node screen', async () => {
await $('#getStartedBtn').click();
const elAddFirstNodeTitle = await $('#addFirstNodeTitle');
await expect(elAddFirstNodeTitle).toBeDisplayed();
await expect(elAddFirstNodeTitle).toHaveText('Add your first node');
});

it('clicking continue btn should take the user to service and initial node settings screen', async () => {
// await browser.pause(3000);
// await $('#getStartedBtn').click();
// await browser.pause(3000);
const alphaModalBtn = (await $('span*=I Understand')).parentElement();
await expect(alphaModalBtn).toBeDisplayed();
await alphaModalBtn.click();
await $('#stepperNextButton').click();
const elAddFirstNodeTitle = await $("#launchAVarNodeTitle");
await expect(elAddFirstNodeTitle).toBeDisplayed();
await expect(elAddFirstNodeTitle).toHaveText('Launch a Ethereum Node');
});

it('clicking continue btn should take the user to service and node requirements screen', async () => {
await $('#stepperNextButton').click();
const elAddFirstNodeTitle = await $("#nodeRequirementsTitle");
await expect(elAddFirstNodeTitle).toBeDisplayed();
await expect(elAddFirstNodeTitle).toHaveText('Node Requirements');
});

// from splash screen, we always show podman screen
it('clicking continue btn should take the user to Podman installation screen', async () => {
await $('#stepperNextButton').click();
await browser.pause(3000); // wait for podman is installed check to return to ui
const elPodmanInstallationTitle = await $("#podmanInstallationTitle");
await expect(elPodmanInstallationTitle).toBeDisplayed();
await expect(elPodmanInstallationTitle).toHaveText('Podman installation');
});

// todo: fix these tests so they can successfully run within a container
// uncomment to run locally
// process.env.CI = 'true';
// || (os.platform() === 'darwin' && process.env.CI === 'true')
// if(os.platform() === 'linux') {
// from splash screen, we always show podman screen
it('clicking continue btn should add and start the node (node status not checked here)', async () => {
await $('#stepperNextButton').click();
}).timeout(120000); // wait 3 minutes for the podman to download (& start)

// it('should pass all of the eth node successfully starts syncing tests:', async () => {
// });
// }
});


await testsForEachNode(); // run tests for first node selection from splash screen

await addNode(); // run tests for adding a node from the add node modal;

// setTimeout(() => {debugger;}, 5000);

6 changes: 3 additions & 3 deletions wdio.conf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export const config: Options.Testrunner = {
// will be called from there.
//
// specs: [['./test/specs/**/*.ts'], ['./test/specs/**/*.ts']],
specs: ['./test/specs/**/*.ts'],
specs: ['./test/specs/ci/**/*.ts'],
// Patterns to exclude.
exclude: [
// 'path/to/excluded/files'
Expand Down Expand Up @@ -101,8 +101,8 @@ export const config: Options.Testrunner = {
// Define all options that are relevant for the WebdriverIO instance here
//
// Level of logging verbosity: trace | debug | info | warn | error | silent
// logLevel: 'info',
logLevel: 'debug',
logLevel: 'info',
// logLevel: 'debug',
//
// Set specific log levels per logger
// loggers:
Expand Down
Loading

0 comments on commit 6476779

Please sign in to comment.