update tests and add code coverage with coverage, although coverage is not required
This commit is contained in:
17
.coveragerc
Normal file
17
.coveragerc
Normal file
@@ -0,0 +1,17 @@
|
||||
[report]
|
||||
exclude_lines =
|
||||
# Skip @abstractmethod
|
||||
@abstractmethod
|
||||
@abc.abstractmethod
|
||||
|
||||
# Don't complain if tests don't hit defensive assertion code:
|
||||
raise AssertionError
|
||||
raise NotImplementedError
|
||||
|
||||
# Don't complain about missing debug-only code:
|
||||
def __repr__
|
||||
if self\.debug
|
||||
|
||||
# Don't complain if non-runnable code isn't run:
|
||||
if 0:
|
||||
if __name__ == .__main__.:
|
||||
@@ -1,54 +0,0 @@
|
||||
# Copyright 2022 Upstream Data Inc
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import unittest
|
||||
|
||||
from pyasic.miners.miner_factory import MINER_CLASSES
|
||||
|
||||
import inspect
|
||||
import sys
|
||||
|
||||
|
||||
class MinersTest(unittest.TestCase):
|
||||
def test_miner_model_creation(self):
|
||||
for miner_model in MINER_CLASSES.keys():
|
||||
for miner_api in MINER_CLASSES[miner_model].keys():
|
||||
with self.subTest(miner_model=miner_model, miner_api=miner_api):
|
||||
miner = MINER_CLASSES[miner_model][miner_api]("0.0.0.0")
|
||||
self.assertTrue(
|
||||
isinstance(miner, MINER_CLASSES[miner_model][miner_api])
|
||||
)
|
||||
|
||||
def test_miner_backend_backup_creation(self):
|
||||
backends = inspect.getmembers(
|
||||
sys.modules["pyasic.miners._backends"], inspect.isclass
|
||||
)
|
||||
for backend in backends:
|
||||
miner_class = backend[1]
|
||||
with self.subTest(miner_class=miner_class):
|
||||
miner = miner_class("0.0.0.0")
|
||||
self.assertTrue(isinstance(miner, miner_class))
|
||||
|
||||
def test_miner_type_creation_failure(self):
|
||||
backends = inspect.getmembers(
|
||||
sys.modules["pyasic.miners._types"], inspect.isclass
|
||||
)
|
||||
for backend in backends:
|
||||
miner_class = backend[1]
|
||||
with self.subTest(miner_class=miner_class):
|
||||
with self.assertRaises(TypeError):
|
||||
miner_class("0.0.0.0")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -13,8 +13,10 @@
|
||||
# limitations under the License.
|
||||
|
||||
import unittest
|
||||
from pyasic.tests.miners_tests import MinersTest
|
||||
from pyasic.tests.network_tests import NetworkTest
|
||||
from tests.miners_tests import MinersTest, MinerFactoryTest
|
||||
from tests.network_tests import NetworkTest
|
||||
from tests.config_tests import ConfigTest
|
||||
|
||||
if __name__ == "__main__":
|
||||
# `coverage run --source pyasic -m unittest discover` will give code coverage data
|
||||
unittest.main()
|
||||
111
tests/config_tests/__init__.py
Normal file
111
tests/config_tests/__init__.py
Normal file
@@ -0,0 +1,111 @@
|
||||
# Copyright 2022 Upstream Data Inc
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import unittest
|
||||
|
||||
from pyasic.config import MinerConfig, _PoolGroup, _Pool # noqa
|
||||
from tests.test_data import (
|
||||
bosminer_api_pools,
|
||||
x19_api_pools,
|
||||
x19_web_pools,
|
||||
bosminer_config_pools,
|
||||
)
|
||||
|
||||
|
||||
class ConfigTest(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.test_config = MinerConfig(
|
||||
pool_groups=[
|
||||
_PoolGroup(
|
||||
quota=1,
|
||||
group_name="TEST",
|
||||
pools=[
|
||||
_Pool(
|
||||
url="stratum+tcp://pyasic.testpool_1.pool:3333",
|
||||
username="pyasic.test",
|
||||
password="123",
|
||||
),
|
||||
_Pool(
|
||||
url="stratum+tcp://pyasic.testpool_2.pool:3333",
|
||||
username="pyasic.test",
|
||||
password="123",
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
temp_mode="auto",
|
||||
temp_target=70.0,
|
||||
temp_hot=80.0,
|
||||
temp_dangerous=100.0,
|
||||
fan_speed=None,
|
||||
autotuning_enabled=True,
|
||||
autotuning_wattage=900,
|
||||
)
|
||||
|
||||
def test_config_from_raw(self):
|
||||
bos_config = MinerConfig().from_raw(bosminer_config_pools)
|
||||
bos_config.pool_groups[0].group_name = "TEST"
|
||||
|
||||
with self.subTest(
|
||||
msg="Testing BOSMiner config file config.", bos_config=bos_config
|
||||
):
|
||||
self.assertEqual(bos_config, self.test_config)
|
||||
|
||||
x19_cfg = MinerConfig().from_raw(x19_web_pools)
|
||||
x19_cfg.pool_groups[0].group_name = "TEST"
|
||||
|
||||
with self.subTest(msg="Testing X19 API config.", x19_cfg=x19_cfg):
|
||||
self.assertEqual(x19_cfg, self.test_config)
|
||||
|
||||
def test_config_from_api(self):
|
||||
bos_cfg = MinerConfig().from_api(bosminer_api_pools["POOLS"])
|
||||
bos_cfg.pool_groups[0].group_name = "TEST"
|
||||
|
||||
with self.subTest(msg="Testing BOSMiner API config.", bos_cfg=bos_cfg):
|
||||
self.assertEqual(bos_cfg, self.test_config)
|
||||
|
||||
x19_cfg = MinerConfig().from_api(x19_api_pools["POOLS"])
|
||||
x19_cfg.pool_groups[0].group_name = "TEST"
|
||||
|
||||
with self.subTest(msg="Testing X19 API config.", x19_cfg=x19_cfg):
|
||||
self.assertEqual(x19_cfg, self.test_config)
|
||||
|
||||
def test_config_as_types(self):
|
||||
cfg = MinerConfig().from_api(bosminer_api_pools["POOLS"])
|
||||
cfg.pool_groups[0].group_name = "TEST"
|
||||
|
||||
commands = [
|
||||
func
|
||||
for func in
|
||||
# each function in self
|
||||
dir(cfg)
|
||||
if callable(getattr(cfg, func)) and
|
||||
# no __ methods
|
||||
not func.startswith("__")
|
||||
]
|
||||
|
||||
for command in [cmd for cmd in commands if cmd.startswith("as_")]:
|
||||
with self.subTest():
|
||||
output = getattr(cfg, command)()
|
||||
self.assertEqual(output, getattr(self.test_config, command)())
|
||||
if f"from_{command.split('as_')[1]}" in commands:
|
||||
self.assertEqual(
|
||||
getattr(MinerConfig(), f"from_{command.split('as_')[1]}")(
|
||||
output
|
||||
),
|
||||
self.test_config,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
162
tests/miners_tests/__init__.py
Normal file
162
tests/miners_tests/__init__.py
Normal file
@@ -0,0 +1,162 @@
|
||||
# Copyright 2022 Upstream Data Inc
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import unittest
|
||||
|
||||
from pyasic.miners.miner_factory import MINER_CLASSES
|
||||
from pyasic.miners.base import BaseMiner
|
||||
from pyasic.miners._backends import CGMiner
|
||||
from pyasic.miners.miner_factory import MinerFactory
|
||||
from pyasic.miners.miner_listener import MinerListener
|
||||
|
||||
import asyncio
|
||||
|
||||
import inspect
|
||||
import sys
|
||||
|
||||
|
||||
class MinersTest(unittest.TestCase):
|
||||
def test_miner_model_creation(self):
|
||||
for miner_model in MINER_CLASSES.keys():
|
||||
for miner_api in MINER_CLASSES[miner_model].keys():
|
||||
with self.subTest(
|
||||
msg=f"Creation of miner using model={miner_model}, api={miner_api}",
|
||||
miner_model=miner_model,
|
||||
miner_api=miner_api,
|
||||
):
|
||||
miner = MINER_CLASSES[miner_model][miner_api]("0.0.0.0")
|
||||
self.assertTrue(
|
||||
isinstance(miner, MINER_CLASSES[miner_model][miner_api])
|
||||
)
|
||||
|
||||
def test_miner_backend_backup_creation(self):
|
||||
backends = inspect.getmembers(
|
||||
sys.modules["pyasic.miners._backends"], inspect.isclass
|
||||
)
|
||||
for backend in backends:
|
||||
miner_class = backend[1]
|
||||
with self.subTest(miner_class=miner_class):
|
||||
miner = miner_class("0.0.0.0")
|
||||
self.assertTrue(isinstance(miner, miner_class))
|
||||
|
||||
def test_miner_type_creation_failure(self):
|
||||
backends = inspect.getmembers(
|
||||
sys.modules["pyasic.miners._types"], inspect.isclass
|
||||
)
|
||||
for backend in backends:
|
||||
miner_class = backend[1]
|
||||
with self.subTest(miner_class=miner_class):
|
||||
with self.assertRaises(TypeError):
|
||||
miner_class("0.0.0.0")
|
||||
with self.assertRaises(TypeError):
|
||||
BaseMiner("0.0.0.0")
|
||||
|
||||
def test_miner_comparisons(self):
|
||||
miner_1 = CGMiner("1.1.1.1")
|
||||
miner_2 = CGMiner("2.2.2.2")
|
||||
miner_3 = CGMiner("1.1.1.1")
|
||||
self.assertEqual(miner_1, miner_3)
|
||||
self.assertGreater(miner_2, miner_1)
|
||||
self.assertLess(miner_3, miner_2)
|
||||
|
||||
|
||||
class MinerFactoryTest(unittest.TestCase):
|
||||
def test_miner_factory_creation(self):
|
||||
self.assertDictEqual(MinerFactory().miners, {})
|
||||
miner_factory = MinerFactory()
|
||||
self.assertIs(MinerFactory(), miner_factory)
|
||||
|
||||
def test_get_miner_generator(self):
|
||||
async def _coro():
|
||||
gen = MinerFactory().get_miner_generator([])
|
||||
miners = []
|
||||
async for miner in gen:
|
||||
miners.append(miner)
|
||||
return miners
|
||||
|
||||
_miners = asyncio.run(_coro())
|
||||
self.assertListEqual(_miners, [])
|
||||
|
||||
def test_miner_selection(self):
|
||||
for miner_model in MINER_CLASSES.keys():
|
||||
with self.subTest():
|
||||
miner = MinerFactory()._select_miner_from_classes(
|
||||
"0.0.0.0", miner_model, None, None
|
||||
)
|
||||
self.assertIsInstance(miner, BaseMiner)
|
||||
for api in ["BOSMiner+", "BOSMiner", "CGMiner", "BTMiner", "BMMiner"]:
|
||||
with self.subTest():
|
||||
miner = MinerFactory()._select_miner_from_classes(
|
||||
"0.0.0.0", None, api, None
|
||||
)
|
||||
self.assertIsInstance(miner, BaseMiner)
|
||||
|
||||
with self.subTest():
|
||||
miner = MinerFactory()._select_miner_from_classes(
|
||||
"0.0.0.0", "ANTMINER S17+", "Fake API", None
|
||||
)
|
||||
self.assertIsInstance(miner, BaseMiner)
|
||||
|
||||
with self.subTest():
|
||||
miner = MinerFactory()._select_miner_from_classes(
|
||||
"0.0.0.0", "M30S", "BTMiner", "G20"
|
||||
)
|
||||
self.assertIsInstance(miner, BaseMiner)
|
||||
|
||||
def test_validate_command(self):
|
||||
bad_test_data_returns = [
|
||||
{},
|
||||
{
|
||||
"cmd": [
|
||||
{
|
||||
"STATUS": [
|
||||
{"STATUS": "E", "Msg": "Command failed for some reason."}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{"STATUS": "E", "Msg": "Command failed for some reason."},
|
||||
{
|
||||
"STATUS": [{"STATUS": "E", "Msg": "Command failed for some reason."}],
|
||||
"id": 1,
|
||||
},
|
||||
]
|
||||
for data in bad_test_data_returns:
|
||||
with self.subTest():
|
||||
|
||||
async def _coro(miner_ret):
|
||||
_data = await MinerFactory()._validate_command(miner_ret)
|
||||
return _data
|
||||
|
||||
ret = asyncio.run(_coro(data))
|
||||
self.assertFalse(ret[0])
|
||||
|
||||
good_test_data_returns = [
|
||||
{
|
||||
"STATUS": [{"STATUS": "S", "Msg": "Yay! Command succeeded."}],
|
||||
"id": 1,
|
||||
},
|
||||
]
|
||||
for data in good_test_data_returns:
|
||||
with self.subTest():
|
||||
|
||||
async def _coro(miner_ret):
|
||||
_data = await MinerFactory()._validate_command(miner_ret)
|
||||
return _data
|
||||
|
||||
ret = asyncio.run(_coro(data))
|
||||
self.assertTrue(ret[0])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -31,8 +31,8 @@ class NetworkTest(unittest.TestCase):
|
||||
"192.168.1.60",
|
||||
]
|
||||
|
||||
net_1 = list(MinerNetworkRange(net_range_str).hosts())
|
||||
net_2 = list(MinerNetworkRange(net_range_list).hosts())
|
||||
net_1 = list(MinerNetwork(net_range_str).get_network().hosts())
|
||||
net_2 = list(MinerNetwork(net_range_list).get_network().hosts())
|
||||
|
||||
correct_net = [
|
||||
ipaddress.IPv4Address("192.168.1.29"),
|
||||
@@ -48,7 +48,7 @@ class NetworkTest(unittest.TestCase):
|
||||
|
||||
def test_net(self):
|
||||
net_1_str = "192.168.1.0"
|
||||
net_1_mask = 29
|
||||
net_1_mask = "/29"
|
||||
|
||||
net_1 = list(MinerNetwork(net_1_str, mask=net_1_mask).get_network().hosts())
|
||||
|
||||
@@ -68,6 +68,20 @@ class NetworkTest(unittest.TestCase):
|
||||
self.assertTrue(net_1 == correct_net)
|
||||
self.assertTrue(net_2 == correct_net)
|
||||
|
||||
def test_net_len(self):
|
||||
net = MinerNetwork("192.168.1.0", mask=32)
|
||||
self.assertEqual(len(net), 1)
|
||||
|
||||
net2 = MinerNetwork("192.168.1.0", mask=31)
|
||||
self.assertEqual(len(net2), 2)
|
||||
|
||||
def test_net_defaults(self):
|
||||
net = MinerNetwork()
|
||||
net_obj = net.get_network()
|
||||
self.assertEqual(net_obj, MinerNetwork("192.168.1.0", mask=24).get_network())
|
||||
|
||||
self.assertEqual(net_obj, net.get_network())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
128
tests/test_data.py
Normal file
128
tests/test_data.py
Normal file
@@ -0,0 +1,128 @@
|
||||
# Copyright 2022 Upstream Data Inc
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
bosminer_api_pools = {
|
||||
"STATUS": [
|
||||
{
|
||||
"STATUS": "S",
|
||||
"Msg": "2 Pool(s)",
|
||||
"Description": "",
|
||||
}
|
||||
],
|
||||
"POOLS": [
|
||||
{
|
||||
"POOL": 0,
|
||||
"URL": "stratum+tcp://pyasic.testpool_1.pool:3333",
|
||||
"Status": "Alive",
|
||||
"Quota": 1,
|
||||
"User": "pyasic.test",
|
||||
"Stratum URL": "pyasic.testpool_1.pool:3333",
|
||||
"AsicBoost": True,
|
||||
},
|
||||
{
|
||||
"POOL": 1,
|
||||
"URL": "stratum+tcp://pyasic.testpool_2.pool:3333",
|
||||
"Status": "Alive",
|
||||
"Quota": 1,
|
||||
"User": "pyasic.test",
|
||||
"Stratum URL": "pyasic.testpool_2.pool:3333",
|
||||
"AsicBoost": True,
|
||||
},
|
||||
],
|
||||
"id": 1,
|
||||
}
|
||||
|
||||
x19_api_pools = {
|
||||
"STATUS": [
|
||||
{
|
||||
"STATUS": "S",
|
||||
"Msg": "2 Pool(s)",
|
||||
"Description": "",
|
||||
}
|
||||
],
|
||||
"POOLS": [
|
||||
{
|
||||
"POOL": 0,
|
||||
"URL": "stratum+tcp://pyasic.testpool_1.pool:3333",
|
||||
"Status": "Alive",
|
||||
"Quota": 1,
|
||||
"User": "pyasic.test",
|
||||
"Stratum URL": "pyasic.testpool_1.pool:3333",
|
||||
},
|
||||
{
|
||||
"POOL": 1,
|
||||
"URL": "stratum+tcp://pyasic.testpool_2.pool:3333",
|
||||
"Status": "Alive",
|
||||
"Quota": 1,
|
||||
"User": "pyasic.test",
|
||||
"Stratum URL": "pyasic.testpool_2.pool:3333",
|
||||
},
|
||||
],
|
||||
"id": 1,
|
||||
}
|
||||
|
||||
x19_web_pools = {
|
||||
"pools": [
|
||||
{
|
||||
"url": "stratum+tcp://pyasic.testpool_1.pool:3333",
|
||||
"user": "pyasic.test",
|
||||
"pass": "123",
|
||||
},
|
||||
{
|
||||
"url": "stratum+tcp://pyasic.testpool_2.pool:3333",
|
||||
"user": "pyasic.test",
|
||||
"pass": "123",
|
||||
},
|
||||
],
|
||||
"api-listen": True,
|
||||
"api-network": True,
|
||||
"api-groups": "A:stats:pools:devs:summary:version",
|
||||
"api-allow": "A:0/0,W:*",
|
||||
"bitmain-fan-ctrl": False,
|
||||
"bitmain-fan-pwm": "100",
|
||||
"bitmain-use-vil": True,
|
||||
"bitmain-freq": "675",
|
||||
"bitmain-voltage": "1400",
|
||||
"bitmain-ccdelay": "0",
|
||||
"bitmain-pwth": "0",
|
||||
"bitmain-work-mode": "0",
|
||||
"bitmain-freq-level": "100",
|
||||
}
|
||||
|
||||
bosminer_config_pools = {
|
||||
"format": {
|
||||
"version": "1.2+",
|
||||
"model": "Antminer S9",
|
||||
"generator": "pyasic",
|
||||
},
|
||||
"group": [
|
||||
{
|
||||
"name": "TEST",
|
||||
"quota": 1,
|
||||
"pool": [
|
||||
{
|
||||
"enabled": True,
|
||||
"url": "stratum+tcp://pyasic.testpool_1.pool:3333",
|
||||
"user": "pyasic.test",
|
||||
"password": "123",
|
||||
},
|
||||
{
|
||||
"enabled": True,
|
||||
"url": "stratum+tcp://pyasic.testpool_2.pool:3333",
|
||||
"user": "pyasic.test",
|
||||
"password": "123",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
Reference in New Issue
Block a user