Skip to content

Commit

Permalink
test_: status cli test migration
Browse files Browse the repository at this point in the history
This reverts commit 4fc9361.

test_: status cli test migration

test_: revert unwanted changes

test_: revert unwanted changes
  • Loading branch information
fbarbu15 committed Nov 9, 2024
1 parent 4fc9361 commit 90b94a2
Show file tree
Hide file tree
Showing 25 changed files with 921 additions and 49 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ __pycache__/
report/results.xml
tests-functional/coverage
tests-functional/reports
tests-functional/local
tests-functional/status-backend
tests-functional/*.log

# generated files
Expand Down
17 changes: 12 additions & 5 deletions tests-functional/README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,22 @@ Functional tests for status-go
- [Overview](#overview)
- [How to Install](#how-to-install)
- [How to Run](#how-to-run)
- [Running Tests](#running-tests)
- [Running Tests](#running-tests)
- [Implementation details](#implementation-details)

## 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

Expand Down
Empty file.
57 changes: 40 additions & 17 deletions tests-functional/clients/signals.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
import json
import logging
import time
from src.libs.common import write_signal_to_file

import websocket

from src.libs.custom_logger import get_custom_logger

logger = get_custom_logger(__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)

if signal_type in self.await_signals:
self.received_signals[signal_type].append(signal_data)

def wait_for_signal(self, signal_type, timeout=20):
start_time = time.time()
Expand All @@ -27,22 +32,40 @@ def wait_for_signal(self, signal_type, timeout=20):
raise TimeoutError(
f"Signal {signal_type} is not received in {timeout} seconds")
time.sleep(0.2)
logging.debug(f"Signal {signal_type} is received in {round(time.time() - start_time)} seconds")
logger.info(f"Signal {signal_type} is received in {round(time.time() - start_time)} seconds")
return self.received_signals[signal_type][0]

def wait_for_complete_signal(self, signal_type, timeout=5):
start_time = time.time()
events = []

while time.time() - start_time < timeout:
if self.received_signals.get(signal_type):
events.extend(self.received_signals[signal_type])
self.received_signals[signal_type] = []
time.sleep(0.2)

if events:
logger.info(
f"Collected {len(events)} events of type {signal_type} within {timeout} seconds")
return events
raise TimeoutError(f"No signals of type {signal_type} 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()
ws.run_forever()
2 changes: 1 addition & 1 deletion tests-functional/clients/status_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from clients.signals import SignalClient
from conftest import option
from constants import user_1
from src.constants import user_1


class RpcClient:
Expand Down
23 changes: 0 additions & 23 deletions tests-functional/constants.py

This file was deleted.

1 change: 1 addition & 0 deletions tests-functional/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ pytest==6.2.4
requests==2.31.0
genson~=1.2.2
websocket-client~=1.4.2
tenacity~=9.0.0
48 changes: 48 additions & 0 deletions tests-functional/src/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import os
import random
from dataclasses import dataclass
from src.libs.common import create_unique_data_dir

@dataclass
class Account:
address: str
private_key: str
password: str
passphrase: str

user_1 = Account(
address="0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
private_key="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
password="Strong12345",
passphrase="test test test test test test test test test test test junk"
)
user_2 = Account(
address="0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
private_key="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d",
password="Strong12345",
passphrase="test test test test test test test test test test nest junk"
)

PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "../.."))
STATUS_BACKEND_URL = os.getenv("STATUS_BACKEND_URL", "http://127.0.0.1")
API_REQUEST_TIMEOUT = int(os.getenv("API_REQUEST_TIMEOUT", "15"))

SOURCE_DIR = os.path.join(PROJECT_ROOT, "cmd/status-backend")
DEST_DIR = os.path.join(PROJECT_ROOT, "tests-functional")
BINARY_PATH = os.path.join(SOURCE_DIR, "status-backend")

DATA_DIR = os.path.join(PROJECT_ROOT, "tests-functional/local")
LOCAL_DATA_DIR1 = create_unique_data_dir(DATA_DIR, random.randint(1, 100))
LOCAL_DATA_DIR2 = create_unique_data_dir(DATA_DIR, random.randint(1, 100))
RESOURCES_FOLDER = os.path.join(PROJECT_ROOT, "resources")

ACCOUNT_PAYLOAD_DEFAULTS = {
"displayName": "user",
"password": "test_password",
"customizationColor": "primary"
}

NUM_CONTACT_REQUESTS = int(os.getenv("NUM_CONTACT_REQUESTS", "5"))
NUM_MESSAGES = int(os.getenv("NUM_MESSAGES", "20"))
DELAY_BETWEEN_MESSAGES = int(os.getenv("NUM_MESSAGES", "1"))
EVENT_SIGNAL_TIMEOUT_SEC = int(os.getenv("EVENT_SIGNAL_TIMEOUT_SEC", "4"))
Empty file.
29 changes: 29 additions & 0 deletions tests-functional/src/libs/base_api_client.py
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
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
65 changes: 65 additions & 0 deletions tests-functional/src/libs/common.py
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 / "build/bin"
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
25 changes: 25 additions & 0 deletions tests-functional/src/libs/custom_logger.py
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.
Loading

0 comments on commit 90b94a2

Please sign in to comment.