-
Notifications
You must be signed in to change notification settings - Fork 256
test_: Code Migration from status-cli-tests #5990
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
Closed
Closed
Changes from 8 commits
Commits
Show all changes
41 commits
Select commit
Hold shift + click to select a range
14dcd29
test_: Code Migration from status-cli-tests
shashankshampi 5de833a
test_: Code Migration from status-cli-tests with develop rebase
shashankshampi c08e922
fix(ci)_: skip windows build cleanup stage
mendelskiv93 5b37466
test_: Code Migration from status-cli-tests with review comments
shashankshampi c8256c2
test_: Code Migration from status-cli-tests with cleanup
shashankshampi 92ff5bf
test_: Code Migration from status-cli-tests with cleanup
shashankshampi 38c1d12
test_: Code Migration from status-cli-tests cleanup
shashankshampi 5d4838a
chore_: remove detection of external swaps and bridges
dlipicar 7617bdd
ci_: configure test jobs (#6008)
igor-sirotin 928daec
test_: Code Migration from status-cli-tests cleanup
shashankshampi 1827420
test_: Code Migration from status-cli-tests addressing review comments
shashankshampi c4bb706
feat(addAmountOutInSentTransactions)_: Add amount out in NewRouterSen…
Khushboo-dev-cpp 89104b3
fix(wallet)_: properly use amount in erc1155 transfers
dlipicar c040cc7
chore(wallet)_: router tx improvements (#6020)
saledjenic 670f17a
test_: Code Migration from status-cli-tests review addressing
shashankshampi 26adbea
test_: Code Migration from status-cli-tests logger removal
shashankshampi 33606e8
test_: Code Migration from status-cli-tests logger removal
shashankshampi e938635
chore_: get version with go generate (#6014)
igor-sirotin 66d612c
test_: Code Migration from status-cli-tests for 1 on 1 message (#6022)
shashankshampi b329b15
fix_: bridge tx improvements
saledjenic 9ecaa2a
test_: profile tests
churik d15ec57
fix_: move version to separate package (#6053)
igor-sirotin f15c64c
chore_: add sentry-go dependency (#6052)
igor-sirotin cfcef92
feat(wallet)_: store route execution data to db
dlipicar 414e08b
chore_: rework transaction code to make it more reusable
dlipicar 1940d26
chore_: adapt route db to new transaction code
dlipicar 4fc9361
fix(wallet)_: broken swap and bridge for erc20 tokens fixed
saledjenic bcef2d6
test_: Code Migration from status-cli-tests
shashankshampi ce3ff64
test_: Code Migration from status-cli-tests with review comments
shashankshampi 4e2fd8f
test_: Code Migration from status-cli-tests with cleanup
shashankshampi 4a663a0
test_: Code Migration from status-cli-tests with cleanup
shashankshampi 9fa435a
test_: Code Migration from status-cli-tests cleanup
shashankshampi 2c38568
test_: Code Migration from status-cli-tests cleanup
shashankshampi dafa903
test_: Code Migration from status-cli-tests addressing review comments
shashankshampi 942a59e
test_: Code Migration from status-cli-tests review addressing
shashankshampi 91e9a86
test_: Code Migration from status-cli-tests logger removal
shashankshampi 8c1d6b1
test_: Code Migration from status-cli-tests logger removal
shashankshampi 386a772
test_: Code Migration from status-cli-tests for 1 on 1 message (#6022)
shashankshampi 31b0a0d
fix: cleanup PR 1
fbarbu15 be1cc0d
Merge remote-tracking branch 'origin/cli_test_migration' into cli_tes…
fbarbu15 184b887
Revert "Merge remote-tracking branch 'origin/cli_test_migration' into…
fbarbu15 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
.idea/ | ||
.local/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,93 @@ | ||
## Overview | ||
|
||
Functional tests for status-go | ||
Functional tests for `status-go` | ||
|
||
## Table of Contents | ||
|
||
- [Overview](#overview) | ||
- [How to Install](#how-to-install) | ||
- [How to Run](#how-to-run) | ||
- [Running Tests](#running-tests) | ||
- [Implementation details](#implementation-details) | ||
- [Implementation Details](#implementation-details) | ||
- [Build Status Backend](#build-status-backend) | ||
|
||
## How to Install | ||
|
||
* Install [Docker](https://docs.docker.com/engine/install/) and [Docker Compose](https://docs.docker.com/compose/install/) | ||
* Install [Python 3.10.14](https://www.python.org/downloads/) | ||
* In `./tests-functional`, run `pip install -r requirements.txt` | ||
* **Optional (for test development)**: Use Python virtual environment for better dependency management. You can follow the guide [here](https://akrabat.com/creating-virtual-environments-with-pyenv/): | ||
1. Install [Docker](https://docs.docker.com/engine/install/) and [Docker Compose](https://docs.docker.com/compose/install/) | ||
2. Install [Python 3.10.14](https://www.python.org/downloads/) | ||
3. **Set up a virtual environment (recommended):** | ||
- In `./tests-functional`, run: | ||
```bash | ||
python3 -m venv .venv | ||
source .venv/bin/activate | ||
pip install -r requirements.txt | ||
``` | ||
- **Optional (for test development)**: Use Python virtual environment for better dependency management. You can follow the guide [here](https://akrabat.com/creating-virtual-environments-with-pyenv/) | ||
|
||
## How to Run | ||
|
||
### Running dev RPC (anvil with contracts) | ||
- In `./tests-functional` run `docker compose -f docker-compose.anvil.yml up --remove-orphans --build`, as result: | ||
* an [anvil](https://book.getfoundry.sh/reference/anvil/) container with ChainID 31337 exposed on `0.0.0.0:8545` will start running | ||
* Status-im contracts will be deployed to the network | ||
### Running dev RPC (Anvil with contracts) | ||
|
||
### Run tests | ||
- In `./tests-functional` run `docker compose -f docker-compose.anvil.yml -f docker-compose.test.status-go.yml -f docker-compose.status-go.local.yml up --build --remove-orphans`, as result: | ||
* a container with [status-go as daemon](https://github.com/status-im/status-go/issues/5175) will be created with APIModules exposed on `0.0.0.0:3333` | ||
* status-go will use [anvil](https://book.getfoundry.sh/reference/anvil/) as RPCURL with ChainID 31337 | ||
* all Status-im contracts will be deployed to the network | ||
In `./tests-functional`: | ||
```bash | ||
docker compose -f docker-compose.anvil.yml up --remove-orphans --build | ||
``` | ||
|
||
* In `./tests-functional/tests` directory run `pytest -m wallet` | ||
This command will: | ||
- Start an [Anvil](https://book.getfoundry.sh/reference/anvil/) container with ChainID `31337`, exposed on `0.0.0.0:8545` | ||
- Deploy Status-im contracts to the Anvil network | ||
|
||
## Implementation details | ||
### Running Tests | ||
|
||
- Functional tests are implemented in `./tests-functional/tests` based on [pytest](https://docs.pytest.org/en/8.2.x/) | ||
- Every test has two types of verifications: | ||
- `verify_is_valid_json_rpc_response()` checks for status code 200, non-empty response, JSON-RPC structure, presence of the `result` field, and expected ID. | ||
- `jsonschema.validate()` is used to check that the response contains expected data, including required fields and types. Schemas are stored in `/schemas/wallet_MethodName` | ||
- New schemas can be generated using `./tests-functional/schema_builder.py` by passing a response to the `CustomSchemaBuilder(schema_name).create_schema(response.json())` method, should be used only on test creation phase, please search `how to create schema:` to see an example in a test | ||
To run the tests: | ||
|
||
1. In `./tests-functional`, start the testing containers: | ||
```bash | ||
docker compose -f docker-compose.anvil.yml -f docker-compose.test.status-go.yml -f docker-compose.status-go.local.yml up --build --remove-orphans | ||
``` | ||
|
||
This command will: | ||
- Create a container with [status-go as daemon](https://github.com/status-im/status-go/issues/5175), exposing `APIModules` on `0.0.0.0:3333` | ||
- Configure `status-go` to use [Anvil](https://book.getfoundry.sh/reference/anvil/) as the `RPCURL` with ChainID `31337` | ||
- Deploy all Status-im contracts to the Anvil network | ||
|
||
2. To execute tests: | ||
- Run all tests: | ||
```bash | ||
pytest | ||
``` | ||
- Run tests marked as `wallet`: | ||
```bash | ||
pytest -m wallet | ||
``` | ||
- Run a specific test: | ||
```bash | ||
pytest -k "test_contact_request_baseline" | ||
``` | ||
|
||
## Implementation Details | ||
|
||
- Functional tests are implemented in `./tests-functional/tests` using [pytest](https://docs.pytest.org/en/8.2.x/). | ||
- Each test performs two types of verifications: | ||
- **`verify_is_valid_json_rpc_response()`**: Checks for a status code `200`, a non-empty response, JSON-RPC structure, presence of the `result` field, and the expected ID. | ||
- **`jsonschema.validate()`**: Validates that the response contains expected data, including required fields and types. Schemas are stored in `/schemas/wallet_MethodName`. | ||
|
||
- **Schema Generation**: | ||
- New schemas can be generated with `./tests-functional/schema_builder.py` by passing a response to the `CustomSchemaBuilder(schema_name).create_schema(response.json())` method. This should be used only during test creation. | ||
- Search `how to create schema:` in test files for examples. | ||
|
||
## Build Status Backend | ||
|
||
You can manually build the binary with the following command in the `status-go` root directory: | ||
|
||
```bash | ||
make status-backend | ||
``` | ||
|
||
For further details on building and setting up `status-go` and `status-backend`, refer to the official documentation: | ||
- [status-backend README](https://github.com/status-im/status-go/blob/develop/cmd/status-backend/README.md) | ||
- [status-go cmd directory](https://github.com/status-im/status-go/tree/develop/cmd/status-backend) | ||
|
||
Location of the binary: `cmd/status-backend/status-backend` | ||
|
||
In test build is automatically being build and placed in right path. If build already exists then new build is not generated. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,48 +1,63 @@ | ||
import json | ||
import logging | ||
import time | ||
from src.libs.common import write_signal_to_file | ||
|
||
import websocket | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
class SignalClient: | ||
|
||
def __init__(self, ws_url, await_signals): | ||
self.url = f"{ws_url}/signals" | ||
|
||
self.await_signals = await_signals | ||
self.received_signals = { | ||
signal: [] for signal in self.await_signals | ||
} | ||
self.received_signals = {signal: [] for signal in self.await_signals} | ||
|
||
def on_message(self, ws, signal): | ||
signal = json.loads(signal) | ||
if signal.get("type") in self.await_signals: | ||
self.received_signals[signal["type"]].append(signal) | ||
signal_data = json.loads(signal) | ||
signal_type = signal_data.get("type") | ||
|
||
write_signal_to_file(signal_data) | ||
|
||
def wait_for_signal(self, signal_type, timeout=20): | ||
if signal_type in self.await_signals: | ||
self.received_signals[signal_type].append(signal_data) | ||
|
||
def wait_for_signal(self, signal_type, expected_event=None, timeout=20): | ||
start_time = time.time() | ||
while not self.received_signals.get(signal_type): | ||
if time.time() - start_time >= timeout: | ||
raise TimeoutError( | ||
f"Signal {signal_type} is not received in {timeout} seconds") | ||
while time.time() - start_time < timeout: | ||
if self.received_signals.get(signal_type): | ||
received_signal = self.received_signals[signal_type][0] | ||
if expected_event: | ||
event = received_signal.get("event", {}) | ||
if all(event.get(k) == v for k, v in expected_event.items()): | ||
logger.info(f"Signal {signal_type} with event {expected_event} received and matched.") | ||
return received_signal | ||
else: | ||
logger.debug( | ||
f"Signal {signal_type} received but event did not match expected event: {expected_event}. Received event: {event}") | ||
else: | ||
logger.info(f"Signal {signal_type} received without specific event validation.") | ||
return received_signal | ||
time.sleep(0.2) | ||
logging.debug(f"Signal {signal_type} is received in {round(time.time() - start_time)} seconds") | ||
return self.received_signals[signal_type][0] | ||
|
||
raise TimeoutError(f"Signal {signal_type} with event {expected_event} not received in {timeout} seconds") | ||
|
||
def _on_error(self, ws, error): | ||
logging.error(f"Error: {error}") | ||
logger.error(f"WebSocket error: {error}") | ||
|
||
def _on_close(self, ws, close_status_code, close_msg): | ||
logging.info(f"Connection closed: {close_status_code}, {close_msg}") | ||
logger.info(f"WebSocket connection closed: {close_status_code}, {close_msg}") | ||
|
||
def _on_open(self, ws): | ||
logging.info("Connection opened") | ||
logger.info("WebSocket connection opened") | ||
|
||
def _connect(self): | ||
ws = websocket.WebSocketApp(self.url, | ||
on_message=self.on_message, | ||
on_error=self._on_error, | ||
on_close=self._on_close) | ||
ws = websocket.WebSocketApp( | ||
self.url, | ||
on_message=self.on_message, | ||
on_error=self._on_error, | ||
on_close=self._on_close | ||
) | ||
ws.on_open = self._on_open | ||
ws.run_forever() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,4 @@ pytest==6.2.4 | |
requests==2.31.0 | ||
genson~=1.2.2 | ||
websocket-client~=1.4.2 | ||
tenacity==8.2.3 |
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import requests | ||
import json | ||
from tenacity import retry, stop_after_delay, wait_fixed | ||
shashankshampi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
from src.libs.custom_logger import get_custom_logger | ||
|
||
logger = get_custom_logger(__name__) | ||
|
||
|
||
class BaseAPIClient: | ||
def __init__(self, base_url): | ||
self.base_url = base_url | ||
|
||
@retry(stop=stop_after_delay(10), wait=wait_fixed(0.5), reraise=True) | ||
def send_post_request(self, endpoint, payload=None, headers=None, timeout=10): | ||
if headers is None: | ||
headers = {"Content-Type": "application/json"} | ||
if payload is None: | ||
payload = {} | ||
|
||
url = f"{self.base_url}/{endpoint}" | ||
logger.info(f"Sending POST request to {url} with payload: {json.dumps(payload)}") | ||
try: | ||
response = requests.post(url, headers=headers, data=json.dumps(payload), timeout=timeout) | ||
response.raise_for_status() | ||
logger.info(f"Response received: {response.status_code} - {response.text}") | ||
return response.json() | ||
except requests.exceptions.RequestException as e: | ||
logger.error(f"Request to {url} failed: {str(e)}") | ||
raise |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
import json | ||
from time import sleep | ||
from src.libs.custom_logger import get_custom_logger | ||
import subprocess | ||
import shutil | ||
import os | ||
import uuid | ||
from datetime import datetime | ||
from pathlib import Path | ||
|
||
logger = get_custom_logger(__name__) | ||
GO_PROJECT_ROOT = Path(__file__).resolve().parents[3] | ||
SOURCE_DIR = GO_PROJECT_ROOT / "cmd/status-backend" | ||
fbarbu15 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
DEST_DIR = GO_PROJECT_ROOT / "tests-functional" | ||
BINARY_PATH = SOURCE_DIR / "status-backend" | ||
REPORTS_DIR = DEST_DIR / "reports" | ||
REPORTS_DIR.mkdir(parents=True, exist_ok=True) | ||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | ||
LOG_FILE_PATH = REPORTS_DIR / f"signals_log_{timestamp}.json" | ||
|
||
|
||
def delay(num_seconds): | ||
logger.debug(f"Sleeping for {num_seconds} seconds") | ||
sleep(num_seconds) | ||
|
||
|
||
def create_unique_data_dir(base_dir: str, index: int) -> str: | ||
unique_id = str(uuid.uuid4())[:8] | ||
unique_dir = os.path.join(base_dir, f"data_{index}_{unique_id}") | ||
os.makedirs(unique_dir, exist_ok=True) | ||
return unique_dir | ||
|
||
|
||
def get_project_root() -> str: | ||
return os.path.abspath(os.path.join(os.path.dirname(__file__), "../../..")) | ||
|
||
|
||
def write_signal_to_file(signal_data): | ||
with open(LOG_FILE_PATH, "a") as file: | ||
json.dump(signal_data, file) | ||
file.write("\n") | ||
|
||
|
||
def build_and_copy_binary(): | ||
logger.info(f"Building status-backend binary in {GO_PROJECT_ROOT}") | ||
result = subprocess.run(["make", "status-backend"], cwd=GO_PROJECT_ROOT, capture_output=True, text=True) | ||
|
||
if result.returncode != 0: | ||
logger.info("Build failed with the following output:") | ||
logger.info(result.stderr) | ||
return False | ||
|
||
if not os.path.exists(BINARY_PATH): | ||
logger.info("Binary build failed or not found! Exiting.") | ||
return False | ||
|
||
logger.info(f"Copying binary to {DEST_DIR}") | ||
shutil.copy(BINARY_PATH, DEST_DIR) | ||
|
||
if os.path.exists(os.path.join(DEST_DIR, "status-backend")): | ||
logger.info("Binary successfully copied to tests-functional directory.") | ||
return True | ||
else: | ||
logger.info("Failed to copy binary to the tests-functional directory.") | ||
return False |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import logging | ||
|
||
max_log_line_length = 10000 | ||
|
||
|
||
def log_length_filter(max_length): | ||
class logLengthFilter(logging.Filter): | ||
def filter(self, record): | ||
if len(record.getMessage()) > max_length: | ||
logging.getLogger(record.name).log( | ||
record.levelno, | ||
f"Log line was discarded because it's longer than max_log_line_length={max_log_line_length}" | ||
) | ||
return False | ||
return True | ||
|
||
return logLengthFilter() | ||
|
||
|
||
def get_custom_logger(name): | ||
logging.getLogger("urllib3").setLevel(logging.WARNING) | ||
logging.getLogger("docker").setLevel(logging.WARNING) | ||
logger = logging.getLogger(name) | ||
logger.addFilter(log_length_filter(max_log_line_length)) | ||
return logger |
Empty file.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.