fix(lint): address ruff lint failures in parallel_subplan_scheduler_steps.py
CI / push-validation (pull_request) Successful in 32s
CI / helm (pull_request) Successful in 41s
CI / build (pull_request) Successful in 56s
CI / lint (pull_request) Failing after 1m9s
CI / quality (pull_request) Successful in 1m29s
CI / typecheck (pull_request) Successful in 1m34s
CI / security (pull_request) Successful in 2m2s
CI / coverage (pull_request) Has been skipped
CI / unit_tests (pull_request) Failing after 3m11s
CI / docker (pull_request) Has been skipped
CI / e2e_tests (pull_request) Successful in 3m41s
CI / integration_tests (pull_request) Successful in 4m36s
CI / status-check (pull_request) Failing after 3s

This commit is contained in:
2026-04-27 09:48:20 +00:00
parent f679ae9faf
commit 2cc4ec0d44
@@ -1,29 +1,15 @@
"""Step definitions for parallel subplan scheduler BDD tests.""" """Step definitions for parallel subplan scheduler BDD tests."""
from __future__ import annotations from __future__ import annotations
import time
from datetime import UTC, datetime from datetime import UTC, datetime
import time
from typing import Any from typing import Any
from unittest.mock import MagicMock
from behave import given, then, when from behave import given, then, when
from cleveragents.application.services.parallel_subplan_scheduler import ( from cleveragents.application.services.parallel_subplan_scheduler import ParallelSubplanScheduler, SchedulerState, SubplanQueue
ParallelSubplanScheduler, from cleveragents.application.services.subplan_execution_service import SubplanExecutionOutput
SchedulerState, from cleveragents.domain.models.core.plan import ExecutionMode, ProcessingState, SubplanConfig, SubplanMergeStrategy, SubplanStatus
SubplanQueue,
)
from cleveragents.application.services.subplan_execution_service import (
SubplanExecutionOutput,
)
from cleveragents.domain.models.core.plan import (
ExecutionMode,
ProcessingState,
SubplanConfig,
SubplanMergeStrategy,
SubplanStatus,
)
# --- Fixtures and helpers --- # --- Fixtures and helpers ---
@@ -53,7 +39,7 @@ def create_executor_fn(
def executor(status: SubplanStatus) -> SubplanExecutionOutput: def executor(status: SubplanStatus) -> SubplanExecutionOutput:
subplan_id = status.subplan_id subplan_id = status.subplan_id
# Track execution for concurrency testing # Track execution for concurrency testing
if not hasattr(context, "concurrent_executions"): if not hasattr(context, "concurrent_executions"):
context.concurrent_executions = [] context.concurrent_executions = []
@@ -61,16 +47,16 @@ def create_executor_fn(
context.execution_start_times = {} context.execution_start_times = {}
if not hasattr(context, "execution_end_times"): if not hasattr(context, "execution_end_times"):
context.execution_end_times = {} context.execution_end_times = {}
context.execution_start_times[subplan_id] = time.time() context.execution_start_times[subplan_id] = time.time()
context.concurrent_executions.append(subplan_id) context.concurrent_executions.append(subplan_id)
# Simulate blocking if configured # Simulate blocking if configured
if subplan_id in block_seconds: if subplan_id in block_seconds:
time.sleep(block_seconds[subplan_id]) time.sleep(block_seconds[subplan_id])
context.execution_end_times[subplan_id] = time.time() context.execution_end_times[subplan_id] = time.time()
# Simulate failure if configured # Simulate failure if configured
if subplan_id in fail_ids: if subplan_id in fail_ids:
return SubplanExecutionOutput( return SubplanExecutionOutput(
@@ -78,7 +64,7 @@ def create_executor_fn(
success=False, success=False,
error="Test failure", error="Test failure",
) )
return SubplanExecutionOutput( return SubplanExecutionOutput(
subplan_id=subplan_id, subplan_id=subplan_id,
success=True, success=True,
@@ -86,7 +72,7 @@ def create_executor_fn(
files_changed=1, files_changed=1,
changeset_summary="Test changes", changeset_summary="Test changes",
) )
return executor return executor
@@ -252,7 +238,7 @@ def step_create_subplans_with_failure(context: Any, count: int) -> None:
create_subplan_status(f"subplan-{i:03d}") create_subplan_status(f"subplan-{i:03d}")
for i in range(count) for i in range(count)
] ]
fail_ids = {f"subplan-001"} fail_ids = {"subplan-001"}
context.scheduler._executor_fn = create_executor_fn(context, fail_ids=fail_ids) context.scheduler._executor_fn = create_executor_fn(context, fail_ids=fail_ids)
@@ -263,7 +249,7 @@ def step_create_subplans_with_first_failure(context: Any, count: int) -> None:
create_subplan_status(f"subplan-{i:03d}") create_subplan_status(f"subplan-{i:03d}")
for i in range(count) for i in range(count)
] ]
fail_ids = {f"subplan-000"} fail_ids = {"subplan-000"}
context.scheduler._executor_fn = create_executor_fn(context, fail_ids=fail_ids) context.scheduler._executor_fn = create_executor_fn(context, fail_ids=fail_ids)
@@ -274,7 +260,7 @@ def step_create_subplans_with_blocking(context: Any, count: int, seconds: int) -
create_subplan_status(f"subplan-{i:03d}") create_subplan_status(f"subplan-{i:03d}")
for i in range(count) for i in range(count)
] ]
block_seconds = {f"subplan-000": seconds} block_seconds = {"subplan-000": seconds}
context.scheduler._executor_fn = create_executor_fn(context, block_seconds=block_seconds) context.scheduler._executor_fn = create_executor_fn(context, block_seconds=block_seconds)
@@ -287,7 +273,7 @@ def step_create_subplans_with_blocking_and_quick(
create_subplan_status(f"subplan-{i:03d}") create_subplan_status(f"subplan-{i:03d}")
for i in range(count) for i in range(count)
] ]
block_seconds = {f"subplan-000": seconds} block_seconds = {"subplan-000": seconds}
context.scheduler._executor_fn = create_executor_fn(context, block_seconds=block_seconds) context.scheduler._executor_fn = create_executor_fn(context, block_seconds=block_seconds)
@@ -495,25 +481,25 @@ def step_check_peak_concurrency(context: Any, max_parallel: int) -> None:
"""Verify peak concurrency doesn't exceed limit.""" """Verify peak concurrency doesn't exceed limit."""
if not hasattr(context, "execution_start_times"): if not hasattr(context, "execution_start_times"):
return # Skip if not tracking return # Skip if not tracking
# Calculate peak concurrency # Calculate peak concurrency
events = [] events = []
for subplan_id, start_time in context.execution_start_times.items(): for subplan_id, start_time in context.execution_start_times.items():
end_time = context.execution_end_times.get(subplan_id, start_time) end_time = context.execution_end_times.get(subplan_id, start_time)
events.append((start_time, "start")) events.append((start_time, "start"))
events.append((end_time, "end")) events.append((end_time, "end"))
events.sort() events.sort()
current_concurrent = 0 current_concurrent = 0
peak_concurrent = 0 peak_concurrent = 0
for _, event_type in events: for _, event_type in events:
if event_type == "start": if event_type == "start":
current_concurrent += 1 current_concurrent += 1
peak_concurrent = max(peak_concurrent, current_concurrent) peak_concurrent = max(peak_concurrent, current_concurrent)
else: else:
current_concurrent -= 1 current_concurrent -= 1
assert peak_concurrent <= max_parallel assert peak_concurrent <= max_parallel
@@ -522,7 +508,7 @@ def step_check_execution_order(context: Any) -> None:
"""Verify subplans executed in order.""" """Verify subplans executed in order."""
if not hasattr(context, "execution_start_times"): if not hasattr(context, "execution_start_times"):
return # Skip if not tracking return # Skip if not tracking
subplan_ids = list(context.execution_start_times.keys()) subplan_ids = list(context.execution_start_times.keys())
for i in range(len(subplan_ids) - 1): for i in range(len(subplan_ids) - 1):
start_i = context.execution_start_times[subplan_ids[i]] start_i = context.execution_start_times[subplan_ids[i]]
@@ -821,7 +807,7 @@ def step_verify_timeout_error(context: Any) -> None:
if status.status == ProcessingState.ERRORED: if status.status == ProcessingState.ERRORED:
assert "timeout" in (status.error or "").lower() assert "timeout" in (status.error or "").lower()
return return
assert False, "No timeout error found" raise AssertionError("No timeout error found")
@then("the second subplan should complete successfully") @then("the second subplan should complete successfully")
@@ -858,11 +844,11 @@ def step_verify_dependency_order(context: Any) -> None:
"""Verify dependency order is respected.""" """Verify dependency order is respected."""
assert context.result is not None assert context.result is not None
status_map = {s.subplan_id: s for s in context.result.statuses} status_map = {s.subplan_id: s for s in context.result.statuses}
# Verify A before B and C # Verify A before B and C
assert status_map["subplan-A"].completed_at < status_map["subplan-B"].completed_at assert status_map["subplan-A"].completed_at < status_map["subplan-B"].completed_at
assert status_map["subplan-A"].completed_at < status_map["subplan-C"].completed_at assert status_map["subplan-A"].completed_at < status_map["subplan-C"].completed_at
# Verify B and C before D # Verify B and C before D
assert status_map["subplan-B"].completed_at < status_map["subplan-D"].completed_at assert status_map["subplan-B"].completed_at < status_map["subplan-D"].completed_at
assert status_map["subplan-C"].completed_at < status_map["subplan-D"].completed_at assert status_map["subplan-C"].completed_at < status_map["subplan-D"].completed_at
@@ -873,25 +859,25 @@ def step_verify_min_concurrency(context: Any, min_concurrent: int) -> None:
"""Verify minimum concurrency.""" """Verify minimum concurrency."""
if not hasattr(context, "execution_start_times"): if not hasattr(context, "execution_start_times"):
return # Skip if not tracking return # Skip if not tracking
# Calculate peak concurrency # Calculate peak concurrency
events = [] events = []
for subplan_id, start_time in context.execution_start_times.items(): for subplan_id, start_time in context.execution_start_times.items():
end_time = context.execution_end_times.get(subplan_id, start_time) end_time = context.execution_end_times.get(subplan_id, start_time)
events.append((start_time, "start")) events.append((start_time, "start"))
events.append((end_time, "end")) events.append((end_time, "end"))
events.sort() events.sort()
current_concurrent = 0 current_concurrent = 0
peak_concurrent = 0 peak_concurrent = 0
for _, event_type in events: for _, event_type in events:
if event_type == "start": if event_type == "start":
current_concurrent += 1 current_concurrent += 1
peak_concurrent = max(peak_concurrent, current_concurrent) peak_concurrent = max(peak_concurrent, current_concurrent)
else: else:
current_concurrent -= 1 current_concurrent -= 1
assert peak_concurrent >= min_concurrent assert peak_concurrent >= min_concurrent
@@ -900,7 +886,7 @@ def step_verify_c_after_ab(context: Any) -> None:
"""Verify C starts after A and B complete.""" """Verify C starts after A and B complete."""
assert context.result is not None assert context.result is not None
status_map = {s.subplan_id: s for s in context.result.statuses} status_map = {s.subplan_id: s for s in context.result.statuses}
# C should start after both A and B complete # C should start after both A and B complete
assert status_map["subplan-C"].started_at > status_map["subplan-A"].completed_at assert status_map["subplan-C"].started_at > status_map["subplan-A"].completed_at
assert status_map["subplan-C"].started_at > status_map["subplan-B"].completed_at assert status_map["subplan-C"].started_at > status_map["subplan-B"].completed_at