test_p0_statistics.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. """
  2. Unit tests for P0 Statistics API endpoints:
  3. - Response Time Percentiles (P99/P95/P50)
  4. - Token Usage Detail (Input/Output breakdown)
  5. - Error Rate
  6. These tests verify the SQL query logic and data transformation
  7. rather than testing the full HTTP endpoint with authentication.
  8. """
  9. from datetime import datetime
  10. import pytest
  11. class TestResponseTimePercentilesStatistic:
  12. """Test suite for Response Time Percentiles SQL and data transformation logic"""
  13. def test_percentile_calculation_logic(self):
  14. """Test that percentile values are correctly converted from seconds to milliseconds"""
  15. # Simulate raw database values (in seconds)
  16. p50_seconds = 0.123
  17. p95_seconds = 0.456
  18. p99_seconds = 0.789
  19. avg_seconds = 0.234
  20. # Apply the transformation logic from the API
  21. p50_ms = round(p50_seconds * 1000, 4)
  22. p95_ms = round(p95_seconds * 1000, 4)
  23. p99_ms = round(p99_seconds * 1000, 4)
  24. avg_ms = round(avg_seconds * 1000, 4)
  25. # Verify conversion
  26. assert p50_ms == 123.0
  27. assert p95_ms == 456.0
  28. assert p99_ms == 789.0
  29. assert avg_ms == 234.0
  30. def test_null_percentile_handling(self):
  31. """Test handling of null percentile values"""
  32. p50_seconds = None
  33. # Apply null handling logic from API
  34. p50_ms = round(p50_seconds * 1000, 4) if p50_seconds else 0
  35. assert p50_ms == 0
  36. def test_sql_query_contains_percentile_functions(self):
  37. """Verify the SQL query includes correct percentile functions"""
  38. from controllers.console.app.statistic import ResponseTimePercentilesStatistic
  39. # Get the source code of the get method
  40. import inspect
  41. source = inspect.getsource(ResponseTimePercentilesStatistic.get)
  42. # Verify SQL contains required percentile functions
  43. assert "PERCENTILE_CONT(0.50)" in source
  44. assert "PERCENTILE_CONT(0.95)" in source
  45. assert "PERCENTILE_CONT(0.99)" in source
  46. assert "provider_response_latency" in source
  47. class TestTokenUsageDetailStatistic:
  48. """Test suite for Token Usage Detail SQL and data transformation logic"""
  49. def test_token_breakdown_logic(self):
  50. """Test that tokens are correctly split into input and output"""
  51. # Simulate database values
  52. input_tokens = 1000
  53. output_tokens = 2000
  54. total_tokens = 3000
  55. # Verify the logic
  56. assert input_tokens + output_tokens == total_tokens
  57. assert input_tokens == 1000
  58. assert output_tokens == 2000
  59. def test_null_token_handling(self):
  60. """Test handling of null token values"""
  61. input_tokens = None
  62. output_tokens = None
  63. # Apply null handling logic from API
  64. input_result = input_tokens or 0
  65. output_result = output_tokens or 0
  66. assert input_result == 0
  67. assert output_result == 0
  68. def test_sql_query_separates_input_output_tokens(self):
  69. """Verify the SQL query correctly separates input and output tokens"""
  70. from controllers.console.app.statistic import TokenUsageDetailStatistic
  71. import inspect
  72. source = inspect.getsource(TokenUsageDetailStatistic.get)
  73. # Verify SQL separates input and output tokens
  74. assert "message_tokens" in source # input tokens
  75. assert "answer_tokens" in source # output tokens
  76. assert "SUM" in source # aggregation function
  77. class TestErrorRateStatistic:
  78. """Test suite for Error Rate calculation logic"""
  79. def test_error_rate_calculation(self):
  80. """Test error rate calculation"""
  81. total_count = 100
  82. error_count = 5
  83. # Apply calculation logic from API
  84. error_rate = (error_count * 100 / total_count) if total_count > 0 else 0
  85. assert error_rate == 5.0 # 5%
  86. def test_zero_requests_error_rate(self):
  87. """Test error rate calculation when total count is zero"""
  88. total_count = 0
  89. error_count = 0
  90. # Should not raise division by zero
  91. error_rate = (error_count * 100 / total_count) if total_count > 0 else 0
  92. assert error_rate == 0.0
  93. def test_100_percent_error_rate(self):
  94. """Test error rate when all requests failed"""
  95. total_count = 50
  96. error_count = 50
  97. error_rate = (error_count * 100 / total_count) if total_count > 0 else 0
  98. assert error_rate == 100.0
  99. def test_partial_error_rate(self):
  100. """Test various partial error rates"""
  101. test_cases = [
  102. (1000, 1, 0.1), # 0.1%
  103. (1000, 10, 1.0), # 1%
  104. (1000, 250, 25.0), # 25%
  105. (100, 33, 33.0), # 33%
  106. ]
  107. for total, errors, expected in test_cases:
  108. error_rate = round((errors * 100 / total) if total > 0 else 0, 2)
  109. assert error_rate == expected
  110. def test_sql_query_identifies_errors(self):
  111. """Verify the SQL query correctly identifies error status"""
  112. from controllers.console.app.statistic import ErrorRateStatistic
  113. import inspect
  114. source = inspect.getsource(ErrorRateStatistic.get)
  115. # Verify SQL checks for error status
  116. assert "status" in source
  117. assert "!=" in source or "<>" in source # SQL not equal operator
  118. assert "normal" in source # status != 'normal' means error