diff --git a/remnawave/models/nodes.py b/remnawave/models/nodes.py index 9ed1acc..15021f9 100644 --- a/remnawave/models/nodes.py +++ b/remnawave/models/nodes.py @@ -150,7 +150,7 @@ class NodeResponseDto(BaseModel): last_status_message: Optional[str] = Field(None, alias="lastStatusMessage") xray_version: Optional[str] = Field(None, alias="xrayVersion") node_version: Optional[str] = Field(None, alias="nodeVersion") - xray_uptime: str = Field(alias="xrayUptime") + xray_uptime: float = Field(0, alias="xrayUptime") is_traffic_tracking_active: bool = Field(alias="isTrafficTrackingActive") traffic_reset_day: Optional[int] = Field(None, alias="trafficResetDay") traffic_limit_bytes: Optional[float] = Field(None, alias="trafficLimitBytes") diff --git a/remnawave/models/subscription.py b/remnawave/models/subscription.py index 0ec8a6f..6a86cb9 100644 --- a/remnawave/models/subscription.py +++ b/remnawave/models/subscription.py @@ -166,7 +166,7 @@ class RawSubscriptionResponse(BaseModel): user: UserResponseDto converted_user_info: ConvertedUserInfo = Field(alias="convertedUserInfo") headers: Dict[str, str] - raw_hosts: List[RawHost] = Field(alias="rawHosts") + raw_hosts: Optional[List[RawHost]] = Field(None, alias="rawHosts") class GetRawSubscriptionByShortUuidResponseDto(RawSubscriptionResponse): diff --git a/remnawave/models/system.py b/remnawave/models/system.py index 69c13d8..42ff921 100644 --- a/remnawave/models/system.py +++ b/remnawave/models/system.py @@ -33,15 +33,15 @@ class BandwidthStatisticResponseDto(BaseModel): class CPUStatistic(BaseModel): cores: float - physical_cores: float = Field(alias="physicalCores") + physical_cores: Optional[float] = Field(None, alias="physicalCores") class MemoryStatistic(BaseModel): total: float free: float used: float - active: float - available: float + active: Optional[float] = None + available: Optional[float] = None class StatusCounts(BaseModel): @@ -112,8 +112,20 @@ class GetNodesStatisticsResponseDto(BaseModel): last_seven_days: List[NodeStatistic] = Field(alias="lastSevenDays") +class RuntimeMetric(BaseModel): + """Runtime metric from health endpoint""" + model_config = {"extra": "allow"} + + rss: Optional[float] = None + heap_total: Optional[float] = Field(None, alias="heapTotal") + heap_used: Optional[float] = Field(None, alias="heapUsed") + external: Optional[float] = None + instance_type: Optional[str] = Field(None, alias="instanceType") + + class GetRemnawaveHealthResponseDto(BaseModel): - pm2_stats: List[PM2Stat] = Field(alias="pm2Stats") + pm2_stats: Optional[List[PM2Stat]] = Field(None, alias="pm2Stats") + runtime_metrics: Optional[List[RuntimeMetric]] = Field(None, alias="runtimeMetrics") class TrafficStatDto(BaseModel): diff --git a/tests/test_bandwidthstats.py b/tests/test_bandwidthstats.py index 305be37..948862d 100644 --- a/tests/test_bandwidthstats.py +++ b/tests/test_bandwidthstats.py @@ -1,5 +1,4 @@ import pytest -from uuid import UUID from remnawave.models import ( # Legacy models (deprecated) @@ -7,11 +6,10 @@ from remnawave.models import ( GetNodesRealtimeUsageResponseDto, GetNodeUserUsageByRangeResponseDto, GetUserUsageByRangeResponseDto, - + # New stats models GetLegacyStatsUserUsageResponseDto, GetLegacyStatsNodesUsersUsageResponseDto, - GetStatsNodesRealtimeUsageResponseDto, GetStatsNodesUsageResponseDto, GetStatsNodeUsersUsageResponseDto, GetStatsUserUsageResponseDto, @@ -69,24 +67,6 @@ async def test_legacy_node_user_usage(remnawave): assert len(node_user_usage) >= 0 -@pytest.mark.asyncio -async def test_stats_nodes_realtime_usage(remnawave): - """Test new stats nodes realtime usage endpoint""" - realtime_usage = await remnawave.bandwidthstats.get_nodes_realtime_usage() - assert isinstance(realtime_usage, GetStatsNodesRealtimeUsageResponseDto) - assert hasattr(realtime_usage, 'response') - assert isinstance(realtime_usage.response, list) - - # Check structure if data exists - if realtime_usage.response: - first_item = realtime_usage.response[0] - assert hasattr(first_item, 'node_uuid') - assert hasattr(first_item, 'node_name') - assert hasattr(first_item, 'download_bytes') - assert hasattr(first_item, 'upload_bytes') - assert hasattr(first_item, 'total_bytes') - - @pytest.mark.asyncio async def test_stats_nodes_usage(remnawave): """Test new stats nodes usage endpoint with charts""" @@ -232,20 +212,7 @@ async def test_legacy_stats_nodes_users_usage(remnawave): async def test_bandwidth_data_structure(remnawave): """Test bandwidth stats data structure validity""" start, end = generate_date_range() - - # Get realtime data - realtime = await remnawave.bandwidthstats.get_nodes_realtime_usage() - - if realtime.response: - # Verify each node has required fields - for node in realtime.response: - assert isinstance(node.node_uuid, UUID) - assert isinstance(node.node_name, str) - assert isinstance(node.download_bytes, (int, float)) - assert isinstance(node.upload_bytes, (int, float)) - assert isinstance(node.total_bytes, (int, float)) - assert node.total_bytes >= 0 - + # Get stats data stats = await remnawave.bandwidthstats.get_stats_nodes_usage( start=start,