mirror of
https://github.com/imartinez/privateGPT.git
synced 2026-07-17 01:48:03 +00:00
197 lines
5.8 KiB
Python
197 lines
5.8 KiB
Python
import itertools
|
|
import time
|
|
from unittest.mock import Mock
|
|
|
|
import pytest
|
|
|
|
from private_gpt.celery.notify import ProgressStatus, ProgressStep, notify_progress
|
|
|
|
PRECISION = 1e-3
|
|
|
|
|
|
class MockProgressStep(ProgressStep):
|
|
STEP_ONE = "step_one"
|
|
STEP_TWO = "step_two"
|
|
STEP_THREE = "step_three"
|
|
|
|
|
|
def test_progress_status_from_percentage():
|
|
# Set the current step for the test
|
|
ProgressStatus.current_step = MockProgressStep.STEP_TWO
|
|
|
|
# Test from_percentage method with 50% in the second step
|
|
result = ProgressStatus.from_percentage(percentage=50)
|
|
|
|
# Calculate the expected percentage:
|
|
expected_percentage = 50
|
|
assert result.percentage == pytest.approx(
|
|
expected_percentage, rel=PRECISION
|
|
), f"The percentage should be close to {expected_percentage}, but got {result.percentage}."
|
|
|
|
|
|
def test_calculate_percentage_out_of_bounds():
|
|
# Test with an out-of-bounds percentage (>100%)
|
|
provided_percentage = 150.0 # More than 100%
|
|
|
|
# Call the static method
|
|
result = ProgressStatus.from_percentage(provided_percentage)
|
|
|
|
# The result should still cap at the maximum percentage for STEP_ONE (33.333%)
|
|
expected_percentage = 100
|
|
assert result.percentage == pytest.approx(
|
|
expected_percentage, rel=PRECISION
|
|
), f"Expected capped percentage to be close to {expected_percentage} for STEP_ONE, but got {result}."
|
|
|
|
|
|
def test_notify_progress():
|
|
# Mock the notify function
|
|
notify_mock = Mock()
|
|
|
|
# Create a status class for testing
|
|
class TestProgressStatus(ProgressStatus):
|
|
current_step = MockProgressStep.STEP_ONE
|
|
|
|
# Use the context manager
|
|
with notify_progress(
|
|
notify=notify_mock,
|
|
status_class=TestProgressStatus,
|
|
start_percentage=10,
|
|
end_percentage=90,
|
|
):
|
|
pass # Simulating the work being done
|
|
|
|
# Ensure notify was called at start and end
|
|
assert (
|
|
notify_mock.call_count == 2
|
|
), "Notify should be called twice, once at start and once at end."
|
|
|
|
# Check that the correct progress was notified at the start
|
|
notify_mock.assert_any_call(TestProgressStatus.from_percentage(percentage=10))
|
|
|
|
# Check that the correct progress was notified at the end
|
|
notify_mock.assert_any_call(
|
|
TestProgressStatus.from_percentage(percentage=90, warnings=[])
|
|
)
|
|
|
|
|
|
def test_notify_progress_with_warnings():
|
|
# Mock the notify function
|
|
notify_mock = Mock()
|
|
|
|
# Create a status class for testing
|
|
class TestProgressStatus(ProgressStatus):
|
|
current_step = MockProgressStep.STEP_ONE
|
|
|
|
# Define some warnings
|
|
warnings = ["Warning 1", "Warning 2"]
|
|
|
|
# Use the context manager with warnings
|
|
with notify_progress(
|
|
notify=notify_mock,
|
|
status_class=TestProgressStatus,
|
|
start_percentage=20,
|
|
end_percentage=100,
|
|
) as progress:
|
|
progress(warnings=warnings)
|
|
|
|
# Check notify was called twice
|
|
assert notify_mock.call_count == 3, "Notify should be called three with warnings."
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("step", "provided_percentage", "expected_result"),
|
|
[
|
|
(
|
|
MockProgressStep.STEP_ONE,
|
|
0,
|
|
0,
|
|
), # 0% into STEP_ONE should give 0% total progress
|
|
(
|
|
MockProgressStep.STEP_ONE,
|
|
50,
|
|
50,
|
|
), # 50% into STEP_ONE should give 50% total progress
|
|
(
|
|
MockProgressStep.STEP_ONE,
|
|
100,
|
|
100,
|
|
), # 100% into STEP_ONE should give 100% total progress
|
|
(
|
|
MockProgressStep.STEP_TWO,
|
|
0,
|
|
0,
|
|
), # 0% into STEP_ONE should give 0% total progress
|
|
(
|
|
MockProgressStep.STEP_TWO,
|
|
50,
|
|
50,
|
|
), # 50% into STEP_ONE should give 50% total progress
|
|
(
|
|
MockProgressStep.STEP_TWO,
|
|
100,
|
|
100,
|
|
), # 100% into STEP_ONE should give 100% total progress
|
|
(
|
|
MockProgressStep.STEP_THREE,
|
|
0,
|
|
0,
|
|
), # 0% into STEP_ONE should give 0% total progress
|
|
(
|
|
MockProgressStep.STEP_THREE,
|
|
50,
|
|
50,
|
|
), # 50% into STEP_ONE should give 50% total progress
|
|
(
|
|
MockProgressStep.STEP_THREE,
|
|
100,
|
|
100,
|
|
), # 100% into STEP_ONE should give 100% total progress
|
|
],
|
|
)
|
|
def test_progress_status_boundary_cases(
|
|
step: MockProgressStep, provided_percentage: float, expected_result: float
|
|
):
|
|
# Set current step for testing
|
|
ProgressStatus.current_step = step
|
|
|
|
# Test from_percentage method with boundary cases
|
|
result = ProgressStatus.from_percentage(percentage=provided_percentage)
|
|
|
|
# Ensure the percentage matches the expected result with a small tolerance
|
|
assert result.percentage == pytest.approx(
|
|
expected_result, rel=PRECISION
|
|
), f"Expected {expected_result}%, but got {result.percentage}%."
|
|
|
|
|
|
def test_fake_generator_progress() -> None:
|
|
notifications: list[float] = []
|
|
start_time = time.time()
|
|
|
|
# Create a status class for testing
|
|
class TestProgressStatus(ProgressStatus):
|
|
current_step = MockProgressStep.STEP_ONE
|
|
|
|
def notify(status: ProgressStatus) -> None:
|
|
notifications.append(status.percentage or 0.0)
|
|
|
|
with notify_progress(
|
|
notify=notify,
|
|
status_class=TestProgressStatus,
|
|
generate_fake_percentage=True,
|
|
generate_fake_percentage_interval_ms=100,
|
|
generate_fake_percentage_jitter=10,
|
|
):
|
|
# Simulate work being done
|
|
time.sleep(0.5)
|
|
|
|
end_time = time.time()
|
|
duration = end_time - start_time
|
|
|
|
assert len(notifications) > 3
|
|
assert notifications[0] == 0.0
|
|
assert notifications[-1] == pytest.approx(
|
|
100, rel=PRECISION
|
|
), f"Expected 100%, but got {notifications[-1]}%."
|
|
assert duration < 1.0
|
|
assert all(x <= y for x, y in itertools.pairwise(notifications))
|