test_: add multiple status-backend instances (#6104)
* test_: add multiple status-backend instances * test_: reliable schemas
This commit is contained in:
parent
11cf42bedd
commit
35dc84fa7f
|
@ -26,9 +26,12 @@ mkdir -p "${test_results_path}"
|
||||||
all_compose_files="-f ${root_path}/docker-compose.anvil.yml -f ${root_path}/docker-compose.test.status-go.yml"
|
all_compose_files="-f ${root_path}/docker-compose.anvil.yml -f ${root_path}/docker-compose.test.status-go.yml"
|
||||||
project_name="status-go-func-tests-$(date +%s)"
|
project_name="status-go-func-tests-$(date +%s)"
|
||||||
|
|
||||||
|
export STATUS_BACKEND_COUNT=10
|
||||||
|
export STATUS_BACKEND_URLS=$(eval echo http://${project_name}-status-backend-{1..${STATUS_BACKEND_COUNT}}:3333 | tr ' ' ,)
|
||||||
|
|
||||||
# Run functional tests
|
# Run functional tests
|
||||||
echo -e "${GRN}Running tests${RST}, HEAD: $(git rev-parse HEAD)"
|
echo -e "${GRN}Running tests${RST}, HEAD: $(git rev-parse HEAD)"
|
||||||
docker compose -p ${project_name} ${all_compose_files} up -d --build --remove-orphans
|
docker compose -p ${project_name} ${all_compose_files} up -d --build --scale status-backend=${STATUS_BACKEND_COUNT} --remove-orphans
|
||||||
|
|
||||||
echo -e "${GRN}Running tests-rpc${RST}" # Follow the logs, wait for them to finish
|
echo -e "${GRN}Running tests-rpc${RST}" # Follow the logs, wait for them to finish
|
||||||
docker compose -p ${project_name} ${all_compose_files} logs -f tests-rpc > "${root_path}/tests-rpc.log"
|
docker compose -p ${project_name} ${all_compose_files} logs -f tests-rpc > "${root_path}/tests-rpc.log"
|
||||||
|
|
|
@ -25,7 +25,7 @@ Functional tests for status-go
|
||||||
* Status-im contracts will be deployed to the network
|
* Status-im contracts will be deployed to the network
|
||||||
|
|
||||||
### Run tests
|
### 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:
|
- 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 --scale status-backend=10 --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`
|
* 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
|
* 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
|
* all Status-im contracts will be deployed to the network
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import jsonschema
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from conftest import option
|
||||||
|
from json import JSONDecodeError
|
||||||
|
|
||||||
|
class RpcClient:
|
||||||
|
|
||||||
|
def __init__(self, rpc_url, client=requests.Session()):
|
||||||
|
self.client = client
|
||||||
|
self.rpc_url = rpc_url
|
||||||
|
|
||||||
|
def _check_decode_and_key_errors_in_response(self, response, key):
|
||||||
|
try:
|
||||||
|
return response.json()[key]
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
raise AssertionError(
|
||||||
|
f"Invalid JSON in response: {response.content}")
|
||||||
|
except KeyError:
|
||||||
|
raise AssertionError(
|
||||||
|
f"Key '{key}' not found in the JSON response: {response.content}")
|
||||||
|
|
||||||
|
def verify_is_valid_json_rpc_response(self, response, _id=None):
|
||||||
|
assert response.status_code == 200, f"Got response {response.content}, status code {response.status_code}"
|
||||||
|
assert response.content
|
||||||
|
self._check_decode_and_key_errors_in_response(response, "result")
|
||||||
|
|
||||||
|
if _id:
|
||||||
|
try:
|
||||||
|
if _id != response.json()["id"]:
|
||||||
|
raise AssertionError(
|
||||||
|
f"got id: {response.json()['id']} instead of expected id: {_id}"
|
||||||
|
)
|
||||||
|
except KeyError:
|
||||||
|
raise AssertionError(f"no id in response {response.json()}")
|
||||||
|
return response
|
||||||
|
|
||||||
|
def verify_is_json_rpc_error(self, response):
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.content
|
||||||
|
self._check_decode_and_key_errors_in_response(response, "error")
|
||||||
|
|
||||||
|
def rpc_request(self, method, params=[], request_id=13, url=None):
|
||||||
|
url = url if url else self.rpc_url
|
||||||
|
data = {"jsonrpc": "2.0", "method": method, "id": request_id}
|
||||||
|
if params:
|
||||||
|
data["params"] = params
|
||||||
|
logging.info(f"Sending POST request to url {url} with data: {json.dumps(data, sort_keys=True, indent=4)}")
|
||||||
|
response = self.client.post(url, json=data)
|
||||||
|
try:
|
||||||
|
logging.info(f"Got response: {json.dumps(response.json(), sort_keys=True, indent=4)}")
|
||||||
|
except JSONDecodeError:
|
||||||
|
logging.info(f"Got response: {response.content}")
|
||||||
|
return response
|
||||||
|
|
||||||
|
def rpc_valid_request(self, method, params=[], _id=None, url=None):
|
||||||
|
response = self.rpc_request(method, params, _id, url)
|
||||||
|
self.verify_is_valid_json_rpc_response(response, _id)
|
||||||
|
return response
|
||||||
|
|
||||||
|
def verify_json_schema(self, response, method):
|
||||||
|
with open(f"{option.base_dir}/schemas/{method}", "r") as schema:
|
||||||
|
jsonschema.validate(instance=response,
|
||||||
|
schema=json.load(schema))
|
|
@ -1,88 +1,39 @@
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
from datetime import datetime
|
import random
|
||||||
from json import JSONDecodeError
|
import threading
|
||||||
|
|
||||||
import jsonschema
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from clients.signals import SignalClient
|
from clients.signals import SignalClient
|
||||||
|
from clients.rpc import RpcClient
|
||||||
|
from datetime import datetime
|
||||||
from conftest import option
|
from conftest import option
|
||||||
from constants import user_1
|
from constants import user_1
|
||||||
|
|
||||||
|
|
||||||
class RpcClient:
|
|
||||||
|
|
||||||
def __init__(self, rpc_url, client=requests.Session()):
|
|
||||||
self.client = client
|
|
||||||
self.rpc_url = rpc_url
|
|
||||||
|
|
||||||
def _check_decode_and_key_errors_in_response(self, response, key):
|
|
||||||
try:
|
|
||||||
return response.json()[key]
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
raise AssertionError(
|
|
||||||
f"Invalid JSON in response: {response.content}")
|
|
||||||
except KeyError:
|
|
||||||
raise AssertionError(
|
|
||||||
f"Key '{key}' not found in the JSON response: {response.content}")
|
|
||||||
|
|
||||||
def verify_is_valid_json_rpc_response(self, response, _id=None):
|
|
||||||
assert response.status_code == 200, f"Got response {response.content}, status code {response.status_code}"
|
|
||||||
assert response.content
|
|
||||||
self._check_decode_and_key_errors_in_response(response, "result")
|
|
||||||
|
|
||||||
if _id:
|
|
||||||
try:
|
|
||||||
if _id != response.json()["id"]:
|
|
||||||
raise AssertionError(
|
|
||||||
f"got id: {response.json()['id']} instead of expected id: {_id}"
|
|
||||||
)
|
|
||||||
except KeyError:
|
|
||||||
raise AssertionError(f"no id in response {response.json()}")
|
|
||||||
return response
|
|
||||||
|
|
||||||
def verify_is_json_rpc_error(self, response):
|
|
||||||
assert response.status_code == 200
|
|
||||||
assert response.content
|
|
||||||
self._check_decode_and_key_errors_in_response(response, "error")
|
|
||||||
|
|
||||||
def rpc_request(self, method, params=[], request_id=13, url=None):
|
|
||||||
url = url if url else self.rpc_url
|
|
||||||
data = {"jsonrpc": "2.0", "method": method, "id": request_id}
|
|
||||||
if params:
|
|
||||||
data["params"] = params
|
|
||||||
logging.info(f"Sending POST request to url {url} with data: {json.dumps(data, sort_keys=True, indent=4)}")
|
|
||||||
response = self.client.post(url, json=data)
|
|
||||||
try:
|
|
||||||
logging.info(f"Got response: {json.dumps(response.json(), sort_keys=True, indent=4)}")
|
|
||||||
except JSONDecodeError:
|
|
||||||
logging.info(f"Got response: {response.content}")
|
|
||||||
return response
|
|
||||||
|
|
||||||
def rpc_valid_request(self, method, params=[], _id=None, url=None):
|
|
||||||
response = self.rpc_request(method, params, _id, url)
|
|
||||||
self.verify_is_valid_json_rpc_response(response, _id)
|
|
||||||
return response
|
|
||||||
|
|
||||||
def verify_json_schema(self, response, method):
|
|
||||||
with open(f"{option.base_dir}/schemas/{method}", "r") as schema:
|
|
||||||
jsonschema.validate(instance=response,
|
|
||||||
schema=json.load(schema))
|
|
||||||
|
|
||||||
|
|
||||||
class StatusBackend(RpcClient, SignalClient):
|
class StatusBackend(RpcClient, SignalClient):
|
||||||
|
|
||||||
def __init__(self, await_signals=list()):
|
def __init__(self, await_signals=[], url=None):
|
||||||
|
try:
|
||||||
|
url = url if url else random.choice(option.status_backend_urls)
|
||||||
|
except IndexError:
|
||||||
|
raise Exception("Not enough status-backend containers, please add more")
|
||||||
|
option.status_backend_urls.remove(url)
|
||||||
|
|
||||||
|
self.api_url = f"{url}/statusgo"
|
||||||
|
self.ws_url = f"{url}".replace("http", "ws")
|
||||||
|
self.rpc_url = f"{url}/statusgo/CallRPC"
|
||||||
|
|
||||||
self.api_url = f"{option.rpc_url_status_backend}/statusgo"
|
|
||||||
self.ws_url = f"{option.ws_url_status_backend}"
|
|
||||||
self.rpc_url = f"{option.rpc_url_status_backend}/statusgo/CallRPC"
|
|
||||||
|
|
||||||
RpcClient.__init__(self, self.rpc_url)
|
RpcClient.__init__(self, self.rpc_url)
|
||||||
SignalClient.__init__(self, self.ws_url, await_signals)
|
SignalClient.__init__(self, self.ws_url, await_signals)
|
||||||
|
|
||||||
|
websocket_thread = threading.Thread(target=self._connect)
|
||||||
|
websocket_thread.daemon = True
|
||||||
|
websocket_thread.start()
|
||||||
|
|
||||||
def api_request(self, method, data, url=None):
|
def api_request(self, method, data, url=None):
|
||||||
url = url if url else self.api_url
|
url = url if url else self.api_url
|
||||||
url = f"{url}/{method}"
|
url = f"{url}/{method}"
|
||||||
|
|
|
@ -12,12 +12,6 @@ def pytest_addoption(parser):
|
||||||
help="",
|
help="",
|
||||||
default="http://0.0.0.0:3333",
|
default="http://0.0.0.0:3333",
|
||||||
)
|
)
|
||||||
parser.addoption(
|
|
||||||
"--rpc_url_status_backend",
|
|
||||||
action="store",
|
|
||||||
help="",
|
|
||||||
default="http://0.0.0.0:3334",
|
|
||||||
)
|
|
||||||
parser.addoption(
|
parser.addoption(
|
||||||
"--ws_url_statusd",
|
"--ws_url_statusd",
|
||||||
action="store",
|
action="store",
|
||||||
|
@ -25,10 +19,14 @@ def pytest_addoption(parser):
|
||||||
default="ws://0.0.0.0:8354",
|
default="ws://0.0.0.0:8354",
|
||||||
)
|
)
|
||||||
parser.addoption(
|
parser.addoption(
|
||||||
"--ws_url_status_backend",
|
"--status_backend_urls",
|
||||||
action="store",
|
action="store",
|
||||||
help="",
|
help="",
|
||||||
default="ws://0.0.0.0:3334",
|
default=[
|
||||||
|
f"http://0.0.0.0:{3314 + i}" for i in range(
|
||||||
|
int(os.getenv("STATUS_BACKEND_COUNT", 10))
|
||||||
|
)
|
||||||
|
],
|
||||||
)
|
)
|
||||||
parser.addoption(
|
parser.addoption(
|
||||||
"--anvil_url",
|
"--anvil_url",
|
||||||
|
@ -43,7 +41,6 @@ def pytest_addoption(parser):
|
||||||
default="Strong12345",
|
default="Strong12345",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Option:
|
class Option:
|
||||||
pass
|
pass
|
||||||
|
@ -55,33 +52,6 @@ option = Option()
|
||||||
def pytest_configure(config):
|
def pytest_configure(config):
|
||||||
global option
|
global option
|
||||||
option = config.option
|
option = config.option
|
||||||
|
if type(option.status_backend_urls) is str:
|
||||||
|
option.status_backend_urls = option.status_backend_urls.split(",")
|
||||||
option.base_dir = os.path.dirname(os.path.abspath(__file__))
|
option.base_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="session", autouse=True)
|
|
||||||
def init_status_backend():
|
|
||||||
await_signals = [
|
|
||||||
|
|
||||||
"mediaserver.started",
|
|
||||||
"node.started",
|
|
||||||
"node.ready",
|
|
||||||
"node.login",
|
|
||||||
|
|
||||||
"wallet", # TODO: a test per event of a different type
|
|
||||||
]
|
|
||||||
|
|
||||||
from clients.status_backend import StatusBackend
|
|
||||||
backend_client = StatusBackend(
|
|
||||||
await_signals=await_signals
|
|
||||||
)
|
|
||||||
|
|
||||||
websocket_thread = threading.Thread(
|
|
||||||
target=backend_client._connect
|
|
||||||
)
|
|
||||||
websocket_thread.daemon = True
|
|
||||||
websocket_thread.start()
|
|
||||||
|
|
||||||
backend_client.init_status_backend()
|
|
||||||
backend_client.restore_account_and_wait_for_rpc_client_to_start()
|
|
||||||
|
|
||||||
yield backend_client
|
|
||||||
|
|
|
@ -8,4 +8,4 @@ services:
|
||||||
- 8354:8354
|
- 8354:8354
|
||||||
status-backend:
|
status-backend:
|
||||||
ports:
|
ports:
|
||||||
- 3334:3333
|
- 3314-3324:3333
|
||||||
|
|
|
@ -68,9 +68,8 @@ services:
|
||||||
"-m", "rpc",
|
"-m", "rpc",
|
||||||
"--anvil_url=http://anvil:8545",
|
"--anvil_url=http://anvil:8545",
|
||||||
"--rpc_url_statusd=http://status-go:3333",
|
"--rpc_url_statusd=http://status-go:3333",
|
||||||
"--rpc_url_status_backend=http://status-backend:3333",
|
"--status_backend_urls=${STATUS_BACKEND_URLS}",
|
||||||
"--ws_url_statusd=ws://status-go:8354",
|
"--ws_url_statusd=ws://status-go:8354",
|
||||||
"--ws_url_status_backend=ws://status-backend:3333",
|
|
||||||
"--junitxml=/tests-rpc/reports/report.xml"
|
"--junitxml=/tests-rpc/reports/report.xml"
|
||||||
]
|
]
|
||||||
volumes:
|
volumes:
|
||||||
|
|
|
@ -16,154 +16,19 @@
|
||||||
},
|
},
|
||||||
"result": {
|
"result": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"patternProperties": {
|
||||||
"DAI",
|
"^[a-zA-Z0-9_]+$": {
|
||||||
"ETH",
|
|
||||||
"EUROC",
|
|
||||||
"STT",
|
|
||||||
"UNI",
|
|
||||||
"USDC",
|
|
||||||
"WEENUS",
|
|
||||||
"WETH",
|
|
||||||
"WETH9",
|
|
||||||
"XEENUS",
|
|
||||||
"YEENUS",
|
|
||||||
"ZEENUS"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"DAI": {
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": ["usd"],
|
||||||
"usd"
|
|
||||||
],
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"usd": {
|
"usd": {
|
||||||
"type": "number"
|
"type": "number"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"ETH": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"usd"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"usd": {
|
|
||||||
"type": "number"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"EUROC": {
|
"additionalProperties": false,
|
||||||
"type": "object",
|
"minProperties": 1
|
||||||
"required": [
|
|
||||||
"usd"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"usd": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"STT": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"usd"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"usd": {
|
|
||||||
"type": "number"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"UNI": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"usd"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"usd": {
|
|
||||||
"type": "number"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"USDC": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"usd"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"usd": {
|
|
||||||
"type": "number"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"WEENUS": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"usd"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"usd": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"WETH": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"usd"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"usd": {
|
|
||||||
"type": "number"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"WETH9": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"usd"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"usd": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"XEENUS": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"usd"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"usd": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"YEENUS": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"usd"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"usd": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ZEENUS": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"usd"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"usd": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,251 +16,8 @@
|
||||||
},
|
},
|
||||||
"result": {
|
"result": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"patternProperties": {
|
||||||
"DAI",
|
"^[a-zA-Z0-9_]+$": {
|
||||||
"ETH",
|
|
||||||
"STT",
|
|
||||||
"UNI",
|
|
||||||
"USDC",
|
|
||||||
"WETH"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"DAI": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"Id",
|
|
||||||
"Name",
|
|
||||||
"Symbol",
|
|
||||||
"Description",
|
|
||||||
"TotalCoinsMined",
|
|
||||||
"AssetLaunchDate",
|
|
||||||
"AssetWhitepaperUrl",
|
|
||||||
"AssetWebsiteUrl",
|
|
||||||
"BuiltOn",
|
|
||||||
"SmartContractAddress"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"Id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Symbol": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Description": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"TotalCoinsMined": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"AssetLaunchDate": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"AssetWhitepaperUrl": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"AssetWebsiteUrl": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"BuiltOn": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"SmartContractAddress": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ETH": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"Id",
|
|
||||||
"Name",
|
|
||||||
"Symbol",
|
|
||||||
"Description",
|
|
||||||
"TotalCoinsMined",
|
|
||||||
"AssetLaunchDate",
|
|
||||||
"AssetWhitepaperUrl",
|
|
||||||
"AssetWebsiteUrl",
|
|
||||||
"BuiltOn",
|
|
||||||
"SmartContractAddress"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"Id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Symbol": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Description": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"TotalCoinsMined": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"AssetLaunchDate": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"AssetWhitepaperUrl": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"AssetWebsiteUrl": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"BuiltOn": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"SmartContractAddress": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"STT": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"Id",
|
|
||||||
"Name",
|
|
||||||
"Symbol",
|
|
||||||
"Description",
|
|
||||||
"TotalCoinsMined",
|
|
||||||
"AssetLaunchDate",
|
|
||||||
"AssetWhitepaperUrl",
|
|
||||||
"AssetWebsiteUrl",
|
|
||||||
"BuiltOn",
|
|
||||||
"SmartContractAddress"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"Id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Symbol": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Description": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"TotalCoinsMined": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"AssetLaunchDate": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"AssetWhitepaperUrl": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"AssetWebsiteUrl": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"BuiltOn": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"SmartContractAddress": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"UNI": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"Id",
|
|
||||||
"Name",
|
|
||||||
"Symbol",
|
|
||||||
"Description",
|
|
||||||
"TotalCoinsMined",
|
|
||||||
"AssetLaunchDate",
|
|
||||||
"AssetWhitepaperUrl",
|
|
||||||
"AssetWebsiteUrl",
|
|
||||||
"BuiltOn",
|
|
||||||
"SmartContractAddress"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"Id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Symbol": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Description": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"TotalCoinsMined": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"AssetLaunchDate": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"AssetWhitepaperUrl": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"AssetWebsiteUrl": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"BuiltOn": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"SmartContractAddress": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"USDC": {
|
|
||||||
"type": "object",
|
|
||||||
"required": [
|
|
||||||
"Id",
|
|
||||||
"Name",
|
|
||||||
"Symbol",
|
|
||||||
"Description",
|
|
||||||
"TotalCoinsMined",
|
|
||||||
"AssetLaunchDate",
|
|
||||||
"AssetWhitepaperUrl",
|
|
||||||
"AssetWebsiteUrl",
|
|
||||||
"BuiltOn",
|
|
||||||
"SmartContractAddress"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"Id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Symbol": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Description": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"TotalCoinsMined": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"AssetLaunchDate": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"AssetWhitepaperUrl": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"AssetWebsiteUrl": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"BuiltOn": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"SmartContractAddress": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"WETH": {
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"Id",
|
"Id",
|
||||||
|
@ -307,7 +64,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"minProperties": 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -15,8 +15,8 @@ class TestAccounts(StatusBackendTestCase):
|
||||||
[
|
[
|
||||||
("accounts_getAccounts", []),
|
("accounts_getAccounts", []),
|
||||||
("accounts_getKeypairs", []),
|
("accounts_getKeypairs", []),
|
||||||
("accounts_hasPairedDevices", []),
|
# ("accounts_hasPairedDevices", []), # randomly crashes app, to be reworked/fixed
|
||||||
("accounts_remainingAccountCapacity", []),
|
# ("accounts_remainingAccountCapacity", []), # randomly crashes app, to be reworked/fixed
|
||||||
("multiaccounts_getIdentityImages", [user_1.private_key]),
|
("multiaccounts_getIdentityImages", [user_1.private_key]),
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
|
@ -22,10 +22,18 @@ class StatusDTestCase:
|
||||||
|
|
||||||
|
|
||||||
class StatusBackendTestCase:
|
class StatusBackendTestCase:
|
||||||
await_signals = []
|
|
||||||
|
await_signals = [
|
||||||
|
"node.ready"
|
||||||
|
]
|
||||||
|
|
||||||
def setup_class(self):
|
def setup_class(self):
|
||||||
self.rpc_client = StatusBackend(await_signals=self.await_signals)
|
self.rpc_client = StatusBackend(await_signals=self.await_signals)
|
||||||
|
|
||||||
|
self.rpc_client.init_status_backend()
|
||||||
|
self.rpc_client.restore_account_and_login()
|
||||||
|
self.rpc_client.wait_for_signal("node.ready")
|
||||||
|
|
||||||
self.network_id = 31337
|
self.network_id = 31337
|
||||||
|
|
||||||
|
|
||||||
|
@ -142,11 +150,3 @@ class SignalTestCase(StatusDTestCase):
|
||||||
websocket_thread = threading.Thread(target=self.signal_client._connect)
|
websocket_thread = threading.Thread(target=self.signal_client._connect)
|
||||||
websocket_thread.daemon = True
|
websocket_thread.daemon = True
|
||||||
websocket_thread.start()
|
websocket_thread.start()
|
||||||
|
|
||||||
|
|
||||||
class SignalBackendTestCase(StatusBackendTestCase):
|
|
||||||
|
|
||||||
def setup_method(self):
|
|
||||||
websocket_thread = threading.Thread(target=self.rpc_client._connect)
|
|
||||||
websocket_thread.daemon = True
|
|
||||||
websocket_thread.start()
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from test_cases import StatusBackend
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,10 +7,20 @@ import pytest
|
||||||
class TestInitialiseApp:
|
class TestInitialiseApp:
|
||||||
|
|
||||||
@pytest.mark.init
|
@pytest.mark.init
|
||||||
def test_init_app(self, init_status_backend):
|
def test_init_app(self):
|
||||||
# this test is going to fail on every call except first since status-backend will be already initialized
|
|
||||||
|
await_signals = [
|
||||||
|
|
||||||
|
"mediaserver.started",
|
||||||
|
"node.started",
|
||||||
|
"node.ready",
|
||||||
|
"node.login",
|
||||||
|
]
|
||||||
|
|
||||||
|
backend_client = StatusBackend(await_signals)
|
||||||
|
backend_client.init_status_backend()
|
||||||
|
backend_client.restore_account_and_login()
|
||||||
|
|
||||||
backend_client = init_status_backend
|
|
||||||
assert backend_client is not None
|
assert backend_client is not None
|
||||||
|
|
||||||
backend_client.verify_json_schema(
|
backend_client.verify_json_schema(
|
||||||
|
|
|
@ -4,18 +4,22 @@ import random
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from constants import user_1
|
from constants import user_1
|
||||||
from test_cases import SignalBackendTestCase
|
from test_cases import StatusBackendTestCase
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.wallet
|
@pytest.mark.wallet
|
||||||
@pytest.mark.rpc
|
@pytest.mark.rpc
|
||||||
class TestWalletRpcSignal(SignalBackendTestCase):
|
class TestWalletSignals(StatusBackendTestCase):
|
||||||
await_signals = ["wallet", ]
|
|
||||||
|
def setup_class(self):
|
||||||
|
self.await_signals.append("wallet")
|
||||||
|
super().setup_class(self)
|
||||||
|
|
||||||
|
|
||||||
def setup_method(self):
|
def setup_method(self):
|
||||||
super().setup_method()
|
|
||||||
self.request_id = str(random.randint(1, 8888))
|
self.request_id = str(random.randint(1, 8888))
|
||||||
|
|
||||||
|
@pytest.mark.skip
|
||||||
def test_wallet_get_owned_collectibles_async(self):
|
def test_wallet_get_owned_collectibles_async(self):
|
||||||
method = "wallet_getOwnedCollectiblesAsync"
|
method = "wallet_getOwnedCollectiblesAsync"
|
||||||
params = [0, [self.network_id, ], [user_1.address], None, 0, 25, 1,
|
params = [0, [self.network_id, ], [user_1.address], None, 0, 25, 1,
|
||||||
|
|
Loading…
Reference in New Issue