Some checks failed
API Endpoint Tests / test-api-endpoints (push) Successful in 11s
CLI Tests / test-cli (push) Failing after 7s
Documentation Validation / validate-docs (push) Successful in 8s
Documentation Validation / validate-policies-strict (push) Successful in 3s
Integration Tests / test-service-integration (push) Successful in 38s
Python Tests / test-python (push) Successful in 11s
Security Scanning / security-scan (push) Successful in 29s
Multi-Node Blockchain Health Monitoring / health-check (push) Successful in 1s
CLI Blockchain Features: - Added block operations: import, export, import-chain, blocks-range - Added messaging system commands (deploy, state, topics, create-topic, messages, post, vote, search, reputation, moderate) - Added network force-sync operation - Replaced marketplace handlers with actual RPC calls - Replaced AI handlers with actual RPC calls - Added account operations (account get) - Added transaction query operations - Added mempool query operations - Created keystore_auth.py for authentication - Removed extended features interception - All handlers use keystore credentials for authenticated endpoints Pool Hub Enhancements: - Added SLA monitoring and capacity tables - Added billing integration service - Added SLA collector service - Added SLA router endpoints - Updated pool hub models and settings - Added integration tests for billing and SLA - Updated documentation with SLA monitoring guide
187 lines
5.8 KiB
Python
187 lines
5.8 KiB
Python
"""
|
|
Tests for SLA Collector Service
|
|
"""
|
|
|
|
import pytest
|
|
from datetime import datetime, timedelta
|
|
from decimal import Decimal
|
|
from sqlalchemy.orm import Session
|
|
|
|
from poolhub.models import Miner, MinerStatus, SLAMetric, SLAViolation, Feedback, MatchResult
|
|
from poolhub.services.sla_collector import SLACollector
|
|
|
|
|
|
@pytest.fixture
|
|
def sla_collector(db_session: Session) -> SLACollector:
|
|
"""Create SLA collector fixture"""
|
|
return SLACollector(db_session)
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_miner(db_session: Session) -> Miner:
|
|
"""Create sample miner fixture"""
|
|
miner = Miner(
|
|
miner_id="test_miner_001",
|
|
api_key_hash="hash123",
|
|
addr="127.0.0.1:8080",
|
|
proto="http",
|
|
gpu_vram_gb=24.0,
|
|
gpu_name="RTX 4090",
|
|
cpu_cores=16,
|
|
ram_gb=64.0,
|
|
max_parallel=4,
|
|
base_price=0.50,
|
|
)
|
|
db_session.add(miner)
|
|
db_session.commit()
|
|
return miner
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_miner_status(db_session: Session, sample_miner: Miner) -> MinerStatus:
|
|
"""Create sample miner status fixture"""
|
|
status = MinerStatus(
|
|
miner_id=sample_miner.miner_id,
|
|
queue_len=2,
|
|
busy=False,
|
|
avg_latency_ms=150,
|
|
temp_c=65,
|
|
mem_free_gb=32.0,
|
|
last_heartbeat_at=datetime.utcnow(),
|
|
)
|
|
db_session.add(status)
|
|
db_session.commit()
|
|
return status
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_record_sla_metric(sla_collector: SLACollector, sample_miner: Miner):
|
|
"""Test recording an SLA metric"""
|
|
metric = await sla_collector.record_sla_metric(
|
|
miner_id=sample_miner.miner_id,
|
|
metric_type="uptime_pct",
|
|
metric_value=98.5,
|
|
metadata={"test": "true"},
|
|
)
|
|
|
|
assert metric.miner_id == sample_miner.miner_id
|
|
assert metric.metric_type == "uptime_pct"
|
|
assert metric.metric_value == 98.5
|
|
assert metric.is_violation == False
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_record_sla_metric_violation(sla_collector: SLACollector, sample_miner: Miner):
|
|
"""Test recording an SLA metric that violates threshold"""
|
|
metric = await sla_collector.record_sla_metric(
|
|
miner_id=sample_miner.miner_id,
|
|
metric_type="uptime_pct",
|
|
metric_value=80.0, # Below threshold of 95%
|
|
metadata={"test": "true"},
|
|
)
|
|
|
|
assert metric.is_violation == True
|
|
|
|
# Check violation was recorded
|
|
violations = await sla_collector.get_sla_violations(
|
|
miner_id=sample_miner.miner_id, resolved=False
|
|
)
|
|
assert len(violations) > 0
|
|
assert violations[0].violation_type == "uptime_pct"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_collect_miner_uptime(sla_collector: SLACollector, sample_miner_status: MinerStatus):
|
|
"""Test collecting miner uptime"""
|
|
uptime = await sla_collector.collect_miner_uptime(sample_miner_status.miner_id)
|
|
|
|
assert uptime is not None
|
|
assert 0 <= uptime <= 100
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_collect_response_time_no_results(sla_collector: SLACollector, sample_miner: Miner):
|
|
"""Test collecting response time when no match results exist"""
|
|
response_time = await sla_collector.collect_response_time(sample_miner.miner_id)
|
|
|
|
assert response_time is None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_collect_completion_rate_no_feedback(sla_collector: SLACollector, sample_miner: Miner):
|
|
"""Test collecting completion rate when no feedback exists"""
|
|
completion_rate = await sla_collector.collect_completion_rate(sample_miner.miner_id)
|
|
|
|
assert completion_rate is None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_collect_capacity_availability(sla_collector: SLACollector):
|
|
"""Test collecting capacity availability"""
|
|
capacity = await sla_collector.collect_capacity_availability()
|
|
|
|
assert "total_miners" in capacity
|
|
assert "active_miners" in capacity
|
|
assert "capacity_availability_pct" in capacity
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_sla_metrics(sla_collector: SLACollector, sample_miner: Miner):
|
|
"""Test getting SLA metrics"""
|
|
# Record a metric first
|
|
await sla_collector.record_sla_metric(
|
|
miner_id=sample_miner.miner_id,
|
|
metric_type="uptime_pct",
|
|
metric_value=98.5,
|
|
)
|
|
|
|
metrics = await sla_collector.get_sla_metrics(
|
|
miner_id=sample_miner.miner_id, hours=24
|
|
)
|
|
|
|
assert len(metrics) > 0
|
|
assert metrics[0].miner_id == sample_miner.miner_id
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_sla_violations(sla_collector: SLACollector, sample_miner: Miner):
|
|
"""Test getting SLA violations"""
|
|
# Record a violation
|
|
await sla_collector.record_sla_metric(
|
|
miner_id=sample_miner.miner_id,
|
|
metric_type="uptime_pct",
|
|
metric_value=80.0, # Below threshold
|
|
)
|
|
|
|
violations = await sla_collector.get_sla_violations(
|
|
miner_id=sample_miner.miner_id, resolved=False
|
|
)
|
|
|
|
assert len(violations) > 0
|
|
|
|
|
|
def test_check_violation_uptime_below_threshold(sla_collector: SLACollector):
|
|
"""Test violation check for uptime below threshold"""
|
|
is_violation = sla_collector._check_violation("uptime_pct", 90.0, 95.0)
|
|
assert is_violation == True
|
|
|
|
|
|
def test_check_violation_uptime_above_threshold(sla_collector: SLACollector):
|
|
"""Test violation check for uptime above threshold"""
|
|
is_violation = sla_collector._check_violation("uptime_pct", 98.0, 95.0)
|
|
assert is_violation == False
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_check_violation_response_time_above_threshold(sla_collector: SLACollector):
|
|
"""Test violation check for response time above threshold"""
|
|
is_violation = sla_collector._check_violation("response_time_ms", 2000.0, 1000.0)
|
|
assert is_violation == True
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_check_violation_response_time_below_threshold(sla_collector: SLACollector):
|
|
"""Test violation check for response time below threshold"""
|
|
is_violation = sla_collector._check_violation("response_time_ms", 500.0, 1000.0)
|
|
assert is_violation == False
|