mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-05-20 23:04:46 -07:00
global: fixes
This commit is contained in:
17
packages/brk_client/tests/mempool_compat/mining/conftest.py
Normal file
17
packages/brk_client/tests/mempool_compat/mining/conftest.py
Normal file
@@ -0,0 +1,17 @@
|
||||
"""Mining-specific fixtures shared by every mining test in this folder."""
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def pool_slugs(mempool):
|
||||
"""Top 3 active pool slugs from the last week."""
|
||||
data = mempool.get_json("/api/v1/mining/pools/1w")
|
||||
pools = data.get("pools", []) if isinstance(data, dict) else []
|
||||
slugs = [p["slug"] for p in pools if p.get("blockCount", 0) > 0][:3]
|
||||
return slugs or ["foundryusa"]
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def pool_slug(pool_slugs):
|
||||
return pool_slugs[0]
|
||||
@@ -0,0 +1,15 @@
|
||||
"""GET /api/v1/mining/blocks/fee-rates/{time_period}"""
|
||||
|
||||
import pytest
|
||||
|
||||
from _lib import assert_same_structure, show, summary
|
||||
|
||||
|
||||
@pytest.mark.parametrize("period", ["24h", "3d", "1w", "1m", "3m", "6m", "1y"])
|
||||
def test_mining_blocks_fee_rates(brk, mempool, period):
|
||||
"""Block fee-rate percentiles must have the same element structure."""
|
||||
path = f"/api/v1/mining/blocks/fee-rates/{period}"
|
||||
b = brk.get_json(path)
|
||||
m = mempool.get_json(path)
|
||||
show("GET", path, summary(b), summary(m))
|
||||
assert_same_structure(b, m)
|
||||
@@ -0,0 +1,15 @@
|
||||
"""GET /api/v1/mining/blocks/fees/{time_period}"""
|
||||
|
||||
import pytest
|
||||
|
||||
from _lib import assert_same_structure, show, summary
|
||||
|
||||
|
||||
@pytest.mark.parametrize("period", ["24h", "3d", "1w", "1m", "3m", "6m", "1y"])
|
||||
def test_mining_blocks_fees(brk, mempool, period):
|
||||
"""Average block fees must have the same element structure."""
|
||||
path = f"/api/v1/mining/blocks/fees/{period}"
|
||||
b = brk.get_json(path)
|
||||
m = mempool.get_json(path)
|
||||
show("GET", path, summary(b), summary(m))
|
||||
assert_same_structure(b, m)
|
||||
@@ -0,0 +1,15 @@
|
||||
"""GET /api/v1/mining/blocks/rewards/{time_period}"""
|
||||
|
||||
import pytest
|
||||
|
||||
from _lib import assert_same_structure, show, summary
|
||||
|
||||
|
||||
@pytest.mark.parametrize("period", ["24h", "3d", "1w", "1m", "3m", "6m", "1y"])
|
||||
def test_mining_blocks_rewards(brk, mempool, period):
|
||||
"""Average block rewards must have the same element structure."""
|
||||
path = f"/api/v1/mining/blocks/rewards/{period}"
|
||||
b = brk.get_json(path)
|
||||
m = mempool.get_json(path)
|
||||
show("GET", path, summary(b), summary(m))
|
||||
assert_same_structure(b, m)
|
||||
@@ -0,0 +1,15 @@
|
||||
"""GET /api/v1/mining/blocks/sizes-weights/{time_period}"""
|
||||
|
||||
import pytest
|
||||
|
||||
from _lib import assert_same_structure, show, summary
|
||||
|
||||
|
||||
@pytest.mark.parametrize("period", ["24h", "3d", "1w", "1m", "3m", "6m", "1y"])
|
||||
def test_mining_blocks_sizes_weights(brk, mempool, period):
|
||||
"""Block sizes and weights must have the same structure."""
|
||||
path = f"/api/v1/mining/blocks/sizes-weights/{period}"
|
||||
b = brk.get_json(path)
|
||||
m = mempool.get_json(path)
|
||||
show("GET", path, summary(b), summary(m))
|
||||
assert_same_structure(b, m)
|
||||
@@ -0,0 +1,15 @@
|
||||
"""GET /api/v1/mining/blocks/timestamp/{timestamp}"""
|
||||
|
||||
from _lib import assert_same_structure, show
|
||||
|
||||
|
||||
def test_mining_blocks_timestamp(brk, mempool, live):
|
||||
"""Block lookup by timestamp must have the same structure for various eras."""
|
||||
for block in live.blocks:
|
||||
info = brk.get_json(f"/api/block/{block.hash}")
|
||||
ts = info["timestamp"]
|
||||
path = f"/api/v1/mining/blocks/timestamp/{ts}"
|
||||
b = brk.get_json(path)
|
||||
m = mempool.get_json(path)
|
||||
show("GET", path, b, m)
|
||||
assert_same_structure(b, m)
|
||||
@@ -0,0 +1,15 @@
|
||||
"""GET /api/v1/mining/difficulty-adjustments/{time_period}"""
|
||||
|
||||
import pytest
|
||||
|
||||
from _lib import assert_same_structure, show, summary
|
||||
|
||||
|
||||
@pytest.mark.parametrize("period", ["24h", "3d", "1w", "1m", "3m", "6m", "1y", "2y", "3y"])
|
||||
def test_mining_difficulty_adjustments(brk, mempool, period):
|
||||
"""Historical difficulty adjustments must have the same structure."""
|
||||
path = f"/api/v1/mining/difficulty-adjustments/{period}"
|
||||
b = brk.get_json(path)
|
||||
m = mempool.get_json(path)
|
||||
show("GET", path, summary(b), summary(m))
|
||||
assert_same_structure(b, m)
|
||||
@@ -0,0 +1,15 @@
|
||||
"""GET /api/v1/mining/hashrate/{time_period}"""
|
||||
|
||||
import pytest
|
||||
|
||||
from _lib import assert_same_structure, show, summary
|
||||
|
||||
|
||||
@pytest.mark.parametrize("period", ["24h", "3d", "1w", "1m", "3m", "6m", "1y", "2y", "3y"])
|
||||
def test_mining_hashrate(brk, mempool, period):
|
||||
"""Network hashrate + difficulty must have the same structure."""
|
||||
path = f"/api/v1/mining/hashrate/{period}"
|
||||
b = brk.get_json(path)
|
||||
m = mempool.get_json(path)
|
||||
show("GET", path, summary(b), summary(m))
|
||||
assert_same_structure(b, m)
|
||||
@@ -0,0 +1,15 @@
|
||||
"""GET /api/v1/mining/hashrate/pools/{time_period}"""
|
||||
|
||||
import pytest
|
||||
|
||||
from _lib import assert_same_structure, show, summary
|
||||
|
||||
|
||||
@pytest.mark.parametrize("period", ["24h", "3d", "1w", "1m", "3m", "1y"])
|
||||
def test_mining_hashrate_pools(brk, mempool, period):
|
||||
"""Per-pool hashrate must have the same structure."""
|
||||
path = f"/api/v1/mining/hashrate/pools/{period}"
|
||||
b = brk.get_json(path)
|
||||
m = mempool.get_json(path)
|
||||
show("GET", path, summary(b), summary(m))
|
||||
assert_same_structure(b, m)
|
||||
13
packages/brk_client/tests/mempool_compat/mining/test_pool.py
Normal file
13
packages/brk_client/tests/mempool_compat/mining/test_pool.py
Normal file
@@ -0,0 +1,13 @@
|
||||
"""GET /api/v1/mining/pool/{slug}"""
|
||||
|
||||
from _lib import assert_same_structure, show, summary
|
||||
|
||||
|
||||
def test_mining_pool_detail(brk, mempool, pool_slugs):
|
||||
"""Pool detail must have the same structure for top pools."""
|
||||
for slug in pool_slugs:
|
||||
path = f"/api/v1/mining/pool/{slug}"
|
||||
b = brk.get_json(path)
|
||||
m = mempool.get_json(path)
|
||||
show("GET", path, summary(b), summary(m))
|
||||
assert_same_structure(b, m)
|
||||
@@ -0,0 +1,15 @@
|
||||
"""GET /api/v1/mining/pool/{slug}/blocks"""
|
||||
|
||||
from _lib import assert_same_structure, show
|
||||
|
||||
|
||||
def test_mining_pool_blocks(brk, mempool, pool_slugs):
|
||||
"""Recent blocks by pool must have the same element structure."""
|
||||
for slug in pool_slugs:
|
||||
path = f"/api/v1/mining/pool/{slug}/blocks"
|
||||
b = brk.get_json(path)
|
||||
m = mempool.get_json(path)
|
||||
show("GET", path, f"({len(b)} blocks)", f"({len(m)} blocks)")
|
||||
assert isinstance(b, list) and isinstance(m, list)
|
||||
if b and m:
|
||||
assert_same_structure(b[0], m[0])
|
||||
@@ -0,0 +1,15 @@
|
||||
"""GET /api/v1/mining/pool/{slug}/blocks/{height}"""
|
||||
|
||||
from _lib import assert_same_structure, show
|
||||
|
||||
|
||||
def test_mining_pool_blocks_at_height(brk, mempool, pool_slug, live):
|
||||
"""Pool blocks before various heights must have the same element structure."""
|
||||
for block in live.blocks[::2]: # every other block, to keep run-time bounded
|
||||
path = f"/api/v1/mining/pool/{pool_slug}/blocks/{block.height}"
|
||||
b = brk.get_json(path)
|
||||
m = mempool.get_json(path)
|
||||
show("GET", path, f"({len(b)} blocks)", f"({len(m)} blocks)")
|
||||
assert isinstance(b, list) and isinstance(m, list)
|
||||
if b and m:
|
||||
assert_same_structure(b[0], m[0])
|
||||
@@ -0,0 +1,13 @@
|
||||
"""GET /api/v1/mining/pool/{slug}/hashrate"""
|
||||
|
||||
from _lib import assert_same_structure, show, summary
|
||||
|
||||
|
||||
def test_mining_pool_hashrate(brk, mempool, pool_slugs):
|
||||
"""Pool hashrate history must have the same structure for top pools."""
|
||||
for slug in pool_slugs:
|
||||
path = f"/api/v1/mining/pool/{slug}/hashrate"
|
||||
b = brk.get_json(path)
|
||||
m = mempool.get_json(path)
|
||||
show("GET", path, summary(b), summary(m))
|
||||
assert_same_structure(b, m)
|
||||
@@ -0,0 +1,45 @@
|
||||
"""GET /api/v1/mining/pools"""
|
||||
|
||||
from _lib import assert_same_structure, show
|
||||
|
||||
|
||||
def test_mining_pools_list_structure(brk, mempool):
|
||||
"""Pool list must have the same element structure."""
|
||||
path = "/api/v1/mining/pools"
|
||||
b = brk.get_json(path)
|
||||
m = mempool.get_json(path)
|
||||
show(
|
||||
"GET", path,
|
||||
b[:3] if isinstance(b, list) else b,
|
||||
m[:3] if isinstance(m, list) else m,
|
||||
)
|
||||
assert_same_structure(b, m)
|
||||
|
||||
|
||||
def _pools(data):
|
||||
"""`pools` may live at the root or inside an envelope across versions."""
|
||||
if isinstance(data, list):
|
||||
return data
|
||||
return data.get("pools", []) if isinstance(data, dict) else []
|
||||
|
||||
|
||||
def test_mining_pools_list_fields(brk):
|
||||
"""Each pool entry must carry slug and name (period-less endpoint omits stats)."""
|
||||
b = _pools(brk.get_json("/api/v1/mining/pools"))
|
||||
show("GET", "/api/v1/mining/pools", f"({len(b)} pools)", "—")
|
||||
assert b, "no pools in brk's response"
|
||||
required = {"slug", "name"}
|
||||
for p in b[:5]:
|
||||
missing = required - set(p.keys())
|
||||
assert not missing, f"pool {p.get('slug', '?')} missing fields: {missing}"
|
||||
assert isinstance(p["name"], str) and p["name"]
|
||||
|
||||
|
||||
def test_mining_pools_slugs_unique(brk):
|
||||
"""Pool slugs must be unique across the response."""
|
||||
b = _pools(brk.get_json("/api/v1/mining/pools"))
|
||||
slugs = [p["slug"] for p in b]
|
||||
show("GET", "/api/v1/mining/pools", f"({len(slugs)} slugs)", "—")
|
||||
assert len(slugs) == len(set(slugs)), (
|
||||
f"duplicate slugs: {len(slugs) - len(set(slugs))}"
|
||||
)
|
||||
@@ -0,0 +1,15 @@
|
||||
"""GET /api/v1/mining/pools/{time_period}"""
|
||||
|
||||
import pytest
|
||||
|
||||
from _lib import assert_same_structure, show, summary
|
||||
|
||||
|
||||
@pytest.mark.parametrize("period", ["24h", "3d", "1w", "1m", "3m", "6m", "1y", "2y", "3y", "all"])
|
||||
def test_mining_pools_by_period(brk, mempool, period):
|
||||
"""Pool stats for a time period must have the same structure."""
|
||||
path = f"/api/v1/mining/pools/{period}"
|
||||
b = brk.get_json(path)
|
||||
m = mempool.get_json(path)
|
||||
show("GET", path, summary(b), summary(m))
|
||||
assert_same_structure(b, m)
|
||||
@@ -0,0 +1,15 @@
|
||||
"""GET /api/v1/mining/reward-stats/{block_count}"""
|
||||
|
||||
import pytest
|
||||
|
||||
from _lib import assert_same_structure, show
|
||||
|
||||
|
||||
@pytest.mark.parametrize("block_count", [10, 100, 500])
|
||||
def test_mining_reward_stats(brk, mempool, block_count):
|
||||
"""Reward stats must have the same structure."""
|
||||
path = f"/api/v1/mining/reward-stats/{block_count}"
|
||||
b = brk.get_json(path)
|
||||
m = mempool.get_json(path)
|
||||
show("GET", path, b, m)
|
||||
assert_same_structure(b, m)
|
||||
Reference in New Issue
Block a user