mirror of
https://github.com/lnbits/lnbits-legend.git
synced 2025-02-25 15:10:41 +01:00
* fix: test data * test: add `status` tests * refactor: try-catch * test: create invoice tests * test: add first `payinvoice` test * test: add pay_invoice error test * feat: allow more test options * test: add pending tests * fix: make check * test: add, pending no fee * fix: make consistent with other API calls * test: more assertions * test: add pending * test: first payment status test * test: pending status * refactor: remove duplicate code * refactor: rename field * chore: code format * chore: uniform
172 lines
4.5 KiB
Python
172 lines
4.5 KiB
Python
from typing import Dict, List, Optional, Union
|
|
|
|
from pydantic import BaseModel
|
|
|
|
|
|
class FundingSourceConfig(BaseModel):
|
|
name: str
|
|
skip: Optional[bool]
|
|
wallet_class: str
|
|
settings: dict
|
|
|
|
|
|
class FunctionMock(BaseModel):
|
|
uri: Optional[str]
|
|
query_params: Optional[dict]
|
|
headers: Optional[dict]
|
|
method: Optional[str]
|
|
|
|
|
|
class TestMock(BaseModel):
|
|
skip: Optional[bool]
|
|
description: Optional[str]
|
|
request_type: Optional[str]
|
|
request_body: Optional[dict]
|
|
response_type: str
|
|
response: Union[str, dict, list]
|
|
|
|
|
|
class Mock(FunctionMock, TestMock):
|
|
name: str
|
|
|
|
@staticmethod
|
|
def combine_mocks(mock_name, fs_mock, test_mock):
|
|
_mock = fs_mock | test_mock
|
|
if "response" in _mock and "response" in fs_mock:
|
|
_mock["response"] |= fs_mock["response"]
|
|
m = Mock(name=mock_name, **_mock)
|
|
|
|
return m
|
|
|
|
|
|
class FunctionMocks(BaseModel):
|
|
mocks: Dict[str, FunctionMock]
|
|
|
|
|
|
class FunctionTest(BaseModel):
|
|
description: str
|
|
call_params: dict
|
|
expect: dict
|
|
mocks: Dict[str, List[Dict[str, TestMock]]]
|
|
|
|
|
|
class FunctionData(BaseModel):
|
|
"""Data required for testing this function"""
|
|
|
|
"Function level mocks that apply for all tests of this function"
|
|
mocks: List[FunctionMock] = []
|
|
|
|
"All the tests for this function"
|
|
tests: List[FunctionTest] = []
|
|
|
|
|
|
class WalletTest(BaseModel):
|
|
skip: Optional[bool]
|
|
function: str
|
|
description: str
|
|
funding_source: FundingSourceConfig
|
|
call_params: Optional[dict] = {}
|
|
expect: Optional[dict]
|
|
expect_error: Optional[dict]
|
|
mocks: List[Mock] = []
|
|
|
|
@staticmethod
|
|
def tests_for_funding_source(
|
|
fs: FundingSourceConfig,
|
|
fn_name: str,
|
|
fn,
|
|
test,
|
|
) -> List["WalletTest"]:
|
|
t = WalletTest(
|
|
**{
|
|
"funding_source": fs,
|
|
"function": fn_name,
|
|
**test,
|
|
"mocks": [],
|
|
"skip": fs.skip,
|
|
}
|
|
)
|
|
if "mocks" in test:
|
|
if fs.name not in test["mocks"]:
|
|
t.skip = True
|
|
return [t]
|
|
|
|
return t._tests_from_fs_mocks(fn, test, fs.name)
|
|
|
|
return [t]
|
|
|
|
def _tests_from_fs_mocks(self, fn, test, fs_name: str) -> List["WalletTest"]:
|
|
|
|
fs_mocks = fn["mocks"][fs_name]
|
|
test_mocks = test["mocks"][fs_name]
|
|
|
|
all_test_mocks = [test_mocks] if isinstance(test_mocks, dict) else test_mocks
|
|
|
|
mocks = []
|
|
for tm in all_test_mocks:
|
|
mocks += self._build_mock_objects(list(fs_mocks), fs_mocks, tm)
|
|
|
|
return [self._tests_from_mock(m) for m in mocks]
|
|
|
|
def _build_mock_objects(self, mock_names, fs_mocks, test_mocks):
|
|
mocks = []
|
|
|
|
for mock_name in mock_names:
|
|
if mock_name not in test_mocks:
|
|
continue
|
|
for test_mock in test_mocks[mock_name]:
|
|
mock = {"fs_mock": fs_mocks[mock_name], "test_mock": test_mock}
|
|
|
|
if len(mock_names) == 1:
|
|
mocks.append({mock_name: mock})
|
|
else:
|
|
sub_mocks = self._build_mock_objects(
|
|
mock_names[1:], fs_mocks, test_mocks
|
|
)
|
|
for sub_mock in sub_mocks:
|
|
mocks.append({mock_name: mock} | sub_mock)
|
|
return mocks
|
|
|
|
return mocks
|
|
|
|
def _tests_from_mock(self, mock_obj) -> "WalletTest":
|
|
|
|
test_mocks: List[Mock] = [
|
|
Mock.combine_mocks(
|
|
mock_name,
|
|
mock_obj[mock_name]["fs_mock"],
|
|
mock_obj[mock_name]["test_mock"],
|
|
)
|
|
for mock_name in mock_obj
|
|
]
|
|
|
|
any_mock_skipped = len([m for m in test_mocks if m.skip])
|
|
extra_description = ";".join(
|
|
[m.description for m in test_mocks if m.description]
|
|
)
|
|
|
|
return WalletTest(
|
|
**(
|
|
self.dict()
|
|
| {
|
|
"description": f"{self.description}:{extra_description}",
|
|
"mocks": test_mocks,
|
|
"skip": self.skip or any_mock_skipped,
|
|
}
|
|
)
|
|
)
|
|
|
|
|
|
class DataObject:
|
|
def __init__(self, **kwargs):
|
|
for k in kwargs:
|
|
setattr(self, k, kwargs[k])
|
|
|
|
def __str__(self):
|
|
data = []
|
|
for k in self.__dict__:
|
|
value = getattr(self, k)
|
|
if isinstance(value, list):
|
|
value = [f"{k}={v}" for v in value]
|
|
data.append(f"{k}={value}")
|
|
return ";".join(data)
|