Skip to content

Commit

Permalink
feat: environment e2e tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jpantos committed Aug 17, 2024
1 parent 0c533d2 commit 0f709b4
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 25 deletions.
16 changes: 13 additions & 3 deletions .github/actions/run-tests/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ inputs:
description: 'The path to the validatornode repository'
required: false
default: ${{ github.workspace }}/validatornode
no-setup:
description: 'Skip the setup steps'
required: false
default: false

runs:
using: 'composite'
Expand All @@ -47,6 +51,7 @@ runs:
working-directory: ${{ env.PANTOS_E2E_TESTS }}

- name: Check for folder existence
if: inputs.no-setup == 'false'
shell: bash
id: check-folder
run: |
Expand All @@ -55,7 +60,7 @@ runs:
echo "PANTOS_VALIDATOR_NODE_EXISTS=$(test -d ${{ env.PANTOS_VALIDATOR_NODE }} && echo true || echo false)" >> $GITHUB_OUTPUT
- uses: actions/checkout@v4
if: steps.check-folder.outputs.PANTOS_ETHEREUM_CONTRACTS_EXISTS == 'false'
if: inputs.no-setup == 'false' && steps.check-folder.outputs.PANTOS_ETHEREUM_CONTRACTS_EXISTS == 'false'
with:
repository: pantos-io/ethereum-contracts
path: ${{ env.PANTOS_ETHEREUM_CONTRACTS }}
Expand All @@ -64,7 +69,7 @@ runs:
Makefile
- uses: actions/checkout@v4
if: steps.check-folder.outputs.PANTOS_SERVICE_NODE_EXISTS == 'false'
if: inputs.no-setup == 'false' && steps.check-folder.outputs.PANTOS_SERVICE_NODE_EXISTS == 'false'
with:
repository: pantos-io/servicenode
path: ${{ env.PANTOS_SERVICE_NODE }}
Expand All @@ -74,7 +79,7 @@ runs:
Makefile
- uses: actions/checkout@v4
if: steps.check-folder.outputs.PANTOS_VALIDATOR_NODE_EXISTS == 'false'
if: inputs.no-setup == 'false' && steps.check-folder.outputs.PANTOS_VALIDATOR_NODE_EXISTS == 'false'
with:
repository: pantos-io/validatornode
path: ${{ env.PANTOS_VALIDATOR_NODE }}
Expand All @@ -84,20 +89,24 @@ runs:
Makefile
- name: Create local signer_key
if: inputs.no-setup == 'false'
shell: bash
run: |
ssh-keygen -t ed25519 -f signer_key.pem -N ''
chmod 777 signer_key.pem
working-directory: ${{ env.PANTOS_SERVICE_NODE }}

- name: Set up QEMU
if: inputs.no-setup == 'false'
uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0

- name: Set up Docker Buildx
if: inputs.no-setup == 'false'
uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0
id: buildx

- name: Cache Docker layers
if: inputs.no-setup == 'false'
uses: actions/cache@v4
with:
path: /tmp/.buildx-cache
Expand All @@ -106,6 +115,7 @@ runs:
${{ runner.os }}-buildx-v1.0-test-
- name: Check docker config and disable live reload
if: inputs.no-setup == 'false'
shell: bash
run: |
cat /etc/docker/daemon.json
Expand Down
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,26 @@ poetry install

Next, make a copy of example.env as .env. Fill in the paths of the dependent projects. You can use the officially built images or alternatively, use locally deployed images.

## How to run
## How to Run Local Tests

To run all the tests, use the following command:

```shell
make test
```

## How to Check an Environment

You can run the tests in environment-check mode by defining the following variables:

```shell
PANTOS_ENV_FILE=<path to the configuration file>
<CHAIN>_PRIVATE_KEY=<either a valid path or the value of the keystore>
<CHAIN>_RECEIVING_ADDRESS=<receiving address for the tests on a specific chain, e.g., ETHEREUM>
```

Once these variables are defined, you can run the tests with:

```shell
make test
```
58 changes: 55 additions & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,26 @@
import dotenv
import pytest
import pantos.client as pc
import pantos.client.library.configuration as pc_conf

if os.getenv('DEBUG', 'false').lower() == 'true':
sys.stdout = sys.stderr

if pathlib.Path('.env').exists():
dotenv.load_dotenv('.env')

existing_env_check = False

@pytest.fixture
def receiving_address():
def receiving_address(request):
global existing_env_check
global env_mapping
network = request.param if request and request.param else 'eth'
if existing_env_check:
address = os.getenv(f'{env_mapping[network].upper()}_RECEIVING_ADDRESS', None)
if not address:
raise EnvironmentError(f'{env_mapping[network].upper()} environment variable not set')
return address
return '0xaAE34Ec313A97265635B8496468928549cdd4AB7'

def generate_random_string(length=5):
Expand All @@ -26,9 +37,35 @@ def generate_random_string(length=5):
def stack_id():
return generate_random_string()

# Temporary until we can fix the naming scheme in the configuration
env_mapping = {
'eth': 'ethereum',
'bnb': 'bnb',
}

chain_mapping = {
'eth': pc.Blockchain.ETHEREUM,
'bnb': pc.Blockchain.BNB_CHAIN,
}

@pytest.fixture
def keystore(request, stack_id):
global existing_env_check
network = request.param if request and request.param else 'eth'
if existing_env_check:
global env_mapping
private_key_name = f'{env_mapping[network].upper()}_PRIVATE_KEY'
resolved_path = os.getenv(private_key_name, None)
if not resolved_path:
raise EnvironmentError(f'Environment keystore for network {network} not found, used {private_key_name}')
try:
with open(resolved_path, 'r') as keystore_file:
keystore = keystore_file.read()
return (keystore, network)
except:
# Assume it's the keystore on its own
return (resolved_path, network)

contracts_dir = os.getenv('PANTOS_ETHEREUM_CONTRACTS')
file = f'{contracts_dir}/data/*{stack_id}-1/{network}/keystore'
resolved_path = glob.glob(file)
Expand All @@ -38,10 +75,25 @@ def keystore(request, stack_id):
raise FileNotFoundError(f'Multiple keystore files found: {resolved_path}')
with open(resolved_path[0], 'r') as keystore_file:
keystore = keystore_file.read()
return keystore
return (keystore, network)

@pytest.fixture
def private_key(keystore):
# Decrypt private key
private_key = pc.decrypt_private_key(pc.Blockchain.ETHEREUM, keystore, '')
global chain_mapping
private_key = pc.decrypt_private_key(chain_mapping[keystore[1]], keystore[0], '')
return private_key

def configure_existing_environment():
global existing_env_check
if not os.getenv('PANTOS_ENV_FILE'):
raise EnvironmentError('PANTOS_ENV_FILE environment variable not set')
file = os.getenv('PANTOS_ENV_FILE')
if not pathlib.Path(file).exists():
raise FileNotFoundError(f'Environment file {file} not found')

dotenv.load_dotenv(file)

pc_conf.load_config(None, True)

existing_env_check = True
1 change: 0 additions & 1 deletion tests/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import os
import pathlib
import subprocess
import sys
import dotenv
import pantos.client.library.configuration as pc_conf
import concurrent.futures
Expand Down
43 changes: 26 additions & 17 deletions tests/test_transfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,33 @@
from pantos.common.servicenodes import ServiceNodeTransferStatus

from helper import configure_client, configure_nodes, teardown_environment
from conftest import configure_existing_environment

test_timeout = int(os.getenv('PYTEST_TIMEOUT', 300)) # 5 minutes

@pytest.fixture(scope="module", autouse=True)
def setup_module(request, stack_id, worker_id = "gw0"):
# Code to set up the environment before any tests in the module
print("Setting up module environment")
port_offset = int(worker_id.replace("gw", "")) if worker_id != "master" else 0
#os.environ['PORT_OFFSET'] = str(port_offset)
configure_nodes({
'ethereum_contracts': {'args': '', 'port_group': port_offset},
'service_node': {'instance_count': 2, 'port_group': port_offset},
'validator_node': {'instance_count': 1, 'port_group': port_offset}
}, stack_id)
configure_client(stack_id)
request.addfinalizer(lambda: teardown_environment(stack_id))
if os.getenv('PANTOS_ENV_FILE', None) is None:
port_offset = int(worker_id.replace("gw", "")) if worker_id != "master" else 0
#os.environ['PORT_OFFSET'] = str(port_offset)
configure_nodes({
'ethereum_contracts': {'args': '', 'port_group': port_offset},
'service_node': {'instance_count': 2, 'port_group': port_offset},
'validator_node': {'instance_count': 1, 'port_group': port_offset}
}, stack_id)
configure_client(stack_id)
request.addfinalizer(lambda: teardown_environment(stack_id))
else:
# Used to check an existing deployment
configure_existing_environment()

@pytest.mark.parametrize('receiving_address', ['bnb'], indirect=True)
def test_retrieve_token_balance(receiving_address):
try:
token_balance = pc.retrieve_token_balance(
pc.Blockchain.BNB_CHAIN,
pc.Blockchain.ETHEREUM,
pc.BlockchainAddress(receiving_address),
pc.TokenSymbol('pan'))
assert token_balance is not None
Expand All @@ -43,22 +51,23 @@ def test_retrieve_service_node_bids():
except pc.PantosClientError:
pytest.fail("PantosClientError raised")

@pytest.mark.timeout(300) # 5 minutes
@pytest.mark.timeout(test_timeout)
@pytest.mark.parametrize('keystore', ['eth'], indirect=True)
@pytest.mark.parametrize('receiving_address', ['bnb'], indirect=True)
def test_token_transfer(receiving_address, private_key):
try:
token_transfer_response = pc.transfer_tokens(
pc.Blockchain.ETHEREUM, pc.Blockchain.BNB_CHAIN, private_key,
pc.BlockchainAddress(receiving_address),
pc.TokenSymbol('pan'), decimal.Decimal('1.01'))
pc.TokenSymbol('pan'), decimal.Decimal('0.000001'))
assert token_transfer_response is not None
print(f'Token transfer response: {token_transfer_response}')
except pc.PantosClientError:
pytest.fail("PantosClientError raised")

try:
done = False
while not done:
done = False
while not done:
try:
token_transfer_status = pc.get_token_transfer_status(
pc.Blockchain.ETHEREUM, token_transfer_response.service_node_address,
token_transfer_response.task_id)
Expand All @@ -71,8 +80,8 @@ def test_token_transfer(receiving_address, private_key):
else:
print('Waiting for transfer to be confirmed...')
time.sleep(5)
except pc.PantosClientError:
pytest.fail("PantosClientError raised")
except pc.PantosClientError:
pytest.fail("PantosClientError raised")

# Enable when we can start the token creator
# @pytest.mark.parametrize('keystore', ['eth'], indirect=True)
Expand Down

0 comments on commit 0f709b4

Please sign in to comment.