Skip to content

LCORE-1472: remove unnecessary steps#1538

Merged
tisnik merged 4 commits into
lightspeed-core:mainfrom
radofuchs:LCORE_1472_remove_unnecessary_steps
Apr 20, 2026
Merged

LCORE-1472: remove unnecessary steps#1538
tisnik merged 4 commits into
lightspeed-core:mainfrom
radofuchs:LCORE_1472_remove_unnecessary_steps

Conversation

@radofuchs
Copy link
Copy Markdown
Contributor

@radofuchs radofuchs commented Apr 19, 2026

Description

Type of change

  • Refactor
  • New feature
  • Bug fix
  • CVE fix
  • Optimization
  • Documentation Update
  • Configuration Update
  • Bump-up service version
  • Bump-up dependent library
  • Bump-up library or tool used for development (does not change the final image)
  • CI configuration change
  • Konflux configuration change
  • Unit tests improvement
  • Integration tests improvement
  • End to end tests improvement
  • Benchmarks improvement

Tools used to create PR

Identify any AI code assistants used in this PR (for transparency and review context)

  • Assisted-by: (e.g., Claude, CodeRabbit, Ollama, etc., N/A if not used)
  • Generated by: (e.g., tool name and version; N/A if not used)

Related Tickets & Documents

  • Related Issue #
  • Closes #

Checklist before requesting a review

  • I have performed a self-review of my code.
  • PR has passed all pre-merge test jobs.
  • If it is a core feature, I have added thorough tests.

Testing

  • Please provide detailed steps to perform tests related to this code change.
  • How were the fix/results from this change verified? Please provide relevant screenshots or results.

Summary by CodeRabbit

Release Notes

  • Tests

    • Refactored test infrastructure for improved scenario-level shield management configuration
    • Consolidated HTTP API test step definitions for streamlined test maintenance
    • Enhanced test cleanup procedures for feedback-related operations
  • Chores

    • Removed obsolete test step definitions
    • Updated test utilities documentation

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 19, 2026

Walkthrough

The PR refactors shield disabling from tag-based annotations to explicit scenario steps, consolidates multiple HTTP step definitions into a single generalized REST API endpoint helper, and updates environment setup to manage cleanup via context flags rather than feature tags. Feedback conversation cleanup registration is added to track conversations for teardown.

Changes

Cohort / File(s) Summary
Shield Disabling Migration
tests/e2e/features/query.feature, tests/e2e/features/streaming_query.feature, tests/e2e/features/steps/shields.py
Replaced @disable-shields tag with explicit Given shields are disabled for this scenario step. New step unregisters llama-guard shield in server mode and stores provider identifiers in context, while skipping scenario in library mode.
Environment Context Management
tests/e2e/features/environment.py
Removed tag-based shield behavior; added per-scenario cleanup of shield context attributes. Updated shield re-registration logic and feedback teardown to depend on context flags (shields_disabled_for_scenario, feedback_e2e_conversation_cleanup, feedback_conversations) instead of feature/scenario tags.
HTTP Step Consolidation
tests/e2e/features/steps/common_http.py
Consolidated 10 disparate HTTP and REST API step definitions into a single generalized step I access REST API endpoint {endpoint} using HTTP {method} method. New step handles both JSON payload (for non-GET/DELETE methods) and URL requests, with auth header attachment when available.
Feedback Conversation Cleanup
tests/e2e/features/steps/feedback.py
Added _register_feedback_conversation_cleanup(context) helper to register cleanup on feedback enable, disable, and conversation creation. Updated feedback status read to use generalized HTTP step instead of removed dedicated method.
Step Definition Removals
tests/e2e/features/steps/health.py, tests/e2e/features/steps/llm_query_response.py
Removed unimplemented stop_service step and two response-checking steps (proper LLM response format, not be truncated).
Documentation Update
tests/e2e/utils/llama_stack_utils.py
Updated module docstring to reference new Given shields are disabled for this scenario step instead of @disable-shields tag.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'LCORE-1472: remove unnecessary steps' is vague and generic; it refers to a real aspect of the change but does not convey what 'unnecessary steps' actually are or why they are being removed. Consider a more specific title that describes the actual change, e.g., 'Refactor shield and feedback e2e tests to use context-based cleanup instead of tags' or 'Replace feature-tag-driven test setup/teardown with context-based scenario management'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/e2e/features/steps/common_http.py (1)

208-233: 🧹 Nitpick | 🔵 Trivial

Normalize method before branching on it.

method is taken verbatim from the Gherkin step, so "Get" or "get" would skip the GET/DELETE branch and then fail the context.text is not None assertion (or try to json.loads a missing payload) even though requests.request itself is case-insensitive. Uppercasing once keeps the step tolerant and intent clear.

♻️ Proposed fix
 `@when`("I access REST API endpoint {endpoint} using HTTP {method} method")
 def access_rest_api_endpoint(context: Context, endpoint: str, method: str) -> None:
     """Send HTTP request with JSON payload to tested service.

     The JSON payload is retrieved from `context.text` attribute,
     which must not be None. The response is stored in
     `context.response` attribute.
     """
     endpoint = normalize_endpoint(endpoint)
     base = f"http://{context.hostname}:{context.port}"
     path = f"{context.api_prefix}/{endpoint}".replace("//", "/")
     url = base + path
 
-    if method in ["GET", "DELETE"]:
+    method = method.upper()
+    if method in ("GET", "DELETE"):
         data = None
     else:
         assert context.text is not None, "Payload needs to be specified"
         data = json.loads(context.text)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/e2e/features/steps/common_http.py` around lines 208 - 233, The
branching on HTTP method in access_rest_api_endpoint uses the raw
Gherkin-provided method string and should be normalized first; update
access_rest_api_endpoint to convert the incoming method to a canonical form
(e.g., method = method.upper()) immediately after receiving the parameter and
before the if method in ["GET", "DELETE"] check so that case-insensitive inputs
like "Get" or "get" follow the correct branch and payload handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/e2e/features/environment.py`:
- Around line 163-170: The manual cleanup loop that deletes context attributes
"shields_disabled_for_scenario", "llama_guard_provider_id", and
"llama_guard_provider_shield_id" is redundant because these are set by the
`@given`("shields are disabled for this scenario") step and live on Behave’s
scenario context; remove the for-loop that calls hasattr/delattr in
environment.py (the block referencing those three attribute names) so the
scenario-layer attributes are allowed to be discarded automatically, and only
re-introduce explicit deletion if you can demonstrate those attributes are being
set on a higher layer outside the shields_are_disabled_for_scenario step.

---

Outside diff comments:
In `@tests/e2e/features/steps/common_http.py`:
- Around line 208-233: The branching on HTTP method in access_rest_api_endpoint
uses the raw Gherkin-provided method string and should be normalized first;
update access_rest_api_endpoint to convert the incoming method to a canonical
form (e.g., method = method.upper()) immediately after receiving the parameter
and before the if method in ["GET", "DELETE"] check so that case-insensitive
inputs like "Get" or "get" follow the correct branch and payload handling.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0d2a930e-3014-46cd-b6dd-4d64c409a54f

📥 Commits

Reviewing files that changed from the base of the PR and between 4b7396d and f4fdbb4.

📒 Files selected for processing (9)
  • tests/e2e/features/environment.py
  • tests/e2e/features/query.feature
  • tests/e2e/features/steps/common_http.py
  • tests/e2e/features/steps/feedback.py
  • tests/e2e/features/steps/health.py
  • tests/e2e/features/steps/llm_query_response.py
  • tests/e2e/features/steps/shields.py
  • tests/e2e/features/streaming_query.feature
  • tests/e2e/utils/llama_stack_utils.py
💤 Files with no reviewable changes (2)
  • tests/e2e/features/steps/llm_query_response.py
  • tests/e2e/features/steps/health.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: build-pr
  • GitHub Check: unit_tests (3.13)
  • GitHub Check: unit_tests (3.12)
  • GitHub Check: Pylinter
  • GitHub Check: E2E: server mode / ci / group 2
  • GitHub Check: E2E: server mode / ci / group 3
  • GitHub Check: E2E: library mode / ci / group 3
  • GitHub Check: E2E: library mode / ci / group 1
  • GitHub Check: E2E: server mode / ci / group 1
  • GitHub Check: E2E: library mode / ci / group 2
  • GitHub Check: E2E Tests for Lightspeed Evaluation job
  • GitHub Check: Konflux kflux-prd-rh02 / lightspeed-stack-on-pull-request
🧰 Additional context used
📓 Path-based instructions (2)
tests/e2e/**/*.{py,feature}

📄 CodeRabbit inference engine (AGENTS.md)

Use behave (BDD) framework for end-to-end testing

Files:

  • tests/e2e/features/query.feature
  • tests/e2e/features/streaming_query.feature
  • tests/e2e/features/steps/shields.py
  • tests/e2e/features/steps/feedback.py
  • tests/e2e/utils/llama_stack_utils.py
  • tests/e2e/features/environment.py
  • tests/e2e/features/steps/common_http.py
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: Use absolute imports for internal modules: from authentication import get_auth_dependency
Import FastAPI dependencies with: from fastapi import APIRouter, HTTPException, Request, status, Depends
Import Llama Stack client with: from llama_stack_client import AsyncLlamaStackClient
Check constants.py for shared constants before defining new ones
All modules start with descriptive docstrings explaining purpose
Use logger = get_logger(__name__) from log.py for module logging
Type aliases defined at module level for clarity
Use Final[type] as type hint for all constants
All functions require docstrings with brief descriptions
Complete type annotations for parameters and return types in functions
Use typing_extensions.Self for model validators in Pydantic models
Use modern union type syntax str | int instead of Union[str, int]
Use Optional[Type] for optional type hints
Use snake_case with descriptive, action-oriented function names (get_, validate_, check_)
Avoid in-place parameter modification anti-patterns; return new data structures instead
Use async def for I/O operations and external API calls
Handle APIConnectionError from Llama Stack in error handling
Use standard log levels with clear purposes: debug, info, warning, error
All classes require descriptive docstrings explaining purpose
Use PascalCase for class names with standard suffixes: Configuration, Error/Exception, Resolver, Interface
Use ABC for abstract base classes with @abstractmethod decorators
Use @model_validator and @field_validator for Pydantic model validation
Complete type annotations for all class attributes; use specific types, not Any
Follow Google Python docstring conventions with Parameters, Returns, Raises, and Attributes sections

Files:

  • tests/e2e/features/steps/shields.py
  • tests/e2e/features/steps/feedback.py
  • tests/e2e/utils/llama_stack_utils.py
  • tests/e2e/features/environment.py
  • tests/e2e/features/steps/common_http.py
🧠 Learnings (4)
📚 Learning: 2026-04-13T13:39:54.963Z
Learnt from: radofuchs
Repo: lightspeed-core/lightspeed-stack PR: 1490
File: tests/e2e/features/environment.py:206-211
Timestamp: 2026-04-13T13:39:54.963Z
Learning: In lightspeed-stack E2E tests under tests/e2e/features, it is intentional to set context.feature_config inside Background/step functions (scenario-scoped Behave layer). The environment.py after_scenario restore logic should only restore configuration when context.scenario_lightspeed_override_active is True; this flag is set by configure_service only when a real config switch occurs (so restore does not run for scenarios without a switch). Additionally, steps/common.py’s module-level _active_lightspeed_stack_config_basename is used to prevent re-applying the same config across subsequent scenarios, ensuring scenario_lightspeed_override_active stays False after the first apply. Therefore, reviewers should not “fix” this flow as if feature_config were incorrectly scoped or if after_scenario restoration is missing—config switching and restoration are meant to happen exactly once per actual switch, not redundantly per scenario.

Applied to files:

  • tests/e2e/features/steps/shields.py
  • tests/e2e/features/steps/feedback.py
  • tests/e2e/features/environment.py
  • tests/e2e/features/steps/common_http.py
📚 Learning: 2026-04-07T09:20:26.590Z
Learnt from: radofuchs
Repo: lightspeed-core/lightspeed-stack PR: 1467
File: tests/e2e/features/steps/common.py:36-49
Timestamp: 2026-04-07T09:20:26.590Z
Learning: For Behave-based Python tests, rely on Behave’s Context layered stack for attribute lifecycle: Behave pushes a new Context layer when entering feature scope (before_feature) and again for scenario scope (before_scenario). Attributes assigned inside given/when/then steps live on the current scenario layer and are automatically removed when the scenario ends. As a result, step-set attributes should not be expected to persist across scenarios or features, and manual cleanup in after_scenario/after_feature is generally unnecessary for attributes set in step functions. Only perform manual cleanup for attributes that you set explicitly in before_feature/before_scenario, since those live on the respective feature/scenario layers.

Applied to files:

  • tests/e2e/features/steps/shields.py
  • tests/e2e/features/steps/feedback.py
  • tests/e2e/features/environment.py
  • tests/e2e/features/steps/common_http.py
📚 Learning: 2025-09-02T11:14:17.117Z
Learnt from: radofuchs
Repo: lightspeed-core/lightspeed-stack PR: 485
File: tests/e2e/features/steps/common_http.py:244-255
Timestamp: 2025-09-02T11:14:17.117Z
Learning: The POST step in tests/e2e/features/steps/common_http.py (`access_rest_api_endpoint_post`) is intentionally designed as a general-purpose HTTP POST method, not specifically for REST API endpoints, so it should not include context.api_prefix in the URL construction.

Applied to files:

  • tests/e2e/features/steps/feedback.py
  • tests/e2e/features/steps/common_http.py
📚 Learning: 2025-08-25T09:05:18.350Z
Learnt from: radofuchs
Repo: lightspeed-core/lightspeed-stack PR: 445
File: tests/e2e/features/health.feature:50-53
Timestamp: 2025-08-25T09:05:18.350Z
Learning: The step definition for ignoring specific fields in response body comparisons is implemented in tests/e2e/features/steps/common_http.py at line 175 as `then('The body of the response, ignoring the "{field}" field, is the following')`.

Applied to files:

  • tests/e2e/features/steps/common_http.py
🪛 Betterleaks (1.1.2)
tests/e2e/features/environment.py

[high] 392-392: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🔇 Additional comments (2)
tests/e2e/features/steps/shields.py (1)

1-37: LGTM!

Clean scenario-scoped implementation: library mode is skipped explicitly, server-mode failure is converted to a scenario skip, and the three context attributes (shields_disabled_for_scenario, llama_guard_provider_id, llama_guard_provider_shield_id) match what environment.after_scenario expects for re-registration. Cleanup of these attributes at before_scenario keeps the flow deterministic across scenarios.

tests/e2e/features/environment.py (1)

372-397: Step-set feedback attributes won't survive into after_feature — cleanup is likely ineffective.

context.feedback_e2e_conversation_cleanup and context.feedback_conversations are set only inside step functions (feedback.py lines 29–31, 155). Per Behave's documented layer mechanics, attributes set in given/when/then steps are stored on the scenario layer and are automatically removed when the scenario ends. Since feedback.feature has multiple scenarios that each create conversations, only the last scenario's attributes will be visible when after_feature runs — intermediate scenarios' conversations will never be deleted.

The before_feature cleanup (lines 373–375) is also ineffective: it only deletes attributes that somehow survived between features, not cleanup within the same feature's scenarios.

Fix: Either initialize these as feature-layer attributes in before_feature (set an empty list/flag that step functions mutate), or move them to module-level in feedback.py (similar to how _active_lightspeed_stack_config_basename is used in common.py).

Comment on lines +163 to +170
# Clear shield unregister state from previous scenarios (see ``shields_are_disabled_for_scenario``).
for _attr in (
"shields_disabled_for_scenario",
"llama_guard_provider_id",
"llama_guard_provider_shield_id",
):
if hasattr(context, _attr):
delattr(context, _attr)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Manual cleanup likely redundant here.

shields_disabled_for_scenario, llama_guard_provider_id, and llama_guard_provider_shield_id are assigned inside the @given("shields are disabled for this scenario") step, so they sit on Behave’s scenario layer and are already discarded when the scenario ends. Unless you’re guarding against something else setting them on a higher layer, this delattr loop can be dropped.

Based on learnings: “step-set attributes should not be expected to persist across scenarios or features, and manual cleanup in after_scenario/after_feature is generally unnecessary for attributes set in step functions.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/e2e/features/environment.py` around lines 163 - 170, The manual cleanup
loop that deletes context attributes "shields_disabled_for_scenario",
"llama_guard_provider_id", and "llama_guard_provider_shield_id" is redundant
because these are set by the `@given`("shields are disabled for this scenario")
step and live on Behave’s scenario context; remove the for-loop that calls
hasattr/delattr in environment.py (the block referencing those three attribute
names) so the scenario-layer attributes are allowed to be discarded
automatically, and only re-introduce explicit deletion if you can demonstrate
those attributes are being set on a higher layer outside the
shields_are_disabled_for_scenario step.

Copy link
Copy Markdown
Contributor

@tisnik tisnik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, nice work

@tisnik tisnik merged commit 75a4495 into lightspeed-core:main Apr 20, 2026
30 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants