Skip to content

Separate out test files to one file per endpoint#295

Merged
PGijsbers merged 7 commits intomainfrom
organize-tests
Mar 27, 2026
Merged

Separate out test files to one file per endpoint#295
PGijsbers merged 7 commits intomainfrom
organize-tests

Conversation

@PGijsbers
Copy link
Copy Markdown
Contributor

Reorganizing the tests to one file per endpoint, because:

  • it's easier to see which conditions are and aren't tested.
  • it's useful to be able to run tests for a specific endpoint, since that's usually the change in a PR.

Tests under migration are left out for now, but will be moved as well.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 27, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 3b0b8dd1-2726-419f-a569-aadd13aa1e7f

📥 Commits

Reviewing files that changed from the base of the PR and between 985aa26 and a548b20.

📒 Files selected for processing (1)
  • tests/routers/openml/study_attach_test.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/routers/openml/study_attach_test.py

Walkthrough

This PR reorganizes OpenML router tests: it removes several existing tests (qualities, some setup/tag, task-type list, and flows_get tests), and adds new dedicated test modules covering flows existence, qualities listing, setup retrieval and tagging, study attachment and creation, and task-type list comparisons. Some raw-SQL helper functions and duplicated HTTP-level comparison tests were removed; new tests use async DB fixtures and API clients. Net change: multiple test files added and removed across the suite.

Possibly related PRs

Suggested labels

tests

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title directly and clearly summarizes the main change: reorganizing test files to have one file per endpoint.
Description check ✅ Passed The description is related to the changeset and explains the rationale for the reorganization of test files.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch organize-tests

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

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • In study_attach_test._attach_tasks_to_study, the UPDATE study SET status = 'in_preparation' WHERE id = 1 statement is hard-coded to id = 1 and ignores the study_id argument, which will cause incorrect behavior if the helper is reused for other study IDs—consider parameterizing the query with study_id.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `study_attach_test._attach_tasks_to_study`, the `UPDATE study SET status = 'in_preparation' WHERE id = 1` statement is hard-coded to `id = 1` and ignores the `study_id` argument, which will cause incorrect behavior if the helper is reused for other study IDs—consider parameterizing the query with `study_id`.

## Individual Comments

### Comment 1
<location path="tests/routers/openml/study_attach_test.py" line_range="20-23" />
<code_context>
+from tests.users import ApiKey
+
+
+async def _attach_tasks_to_study(
+    study_id: int,
+    task_ids: list[int],
+    api_key: str,
+    py_api: httpx.AsyncClient,
+    expdb_test: AsyncConnection,
+) -> httpx.Response:
+    # Adding requires the study to be in preparation,
+    # but the current snapshot has no in-preparation studies.
+    await expdb_test.execute(text("UPDATE study SET status = 'in_preparation' WHERE id = 1"))
+    return await py_api.post(
+        f"/studies/attach?api_key={api_key}",
</code_context>
<issue_to_address>
**suggestion:** Use `study_id` parameter instead of hard-coded `id = 1` to make the helper more robust and self-consistent

The helper takes a `study_id` argument but the SQL still hard-codes `WHERE id = 1`, which couples it to current usages and makes future calls with other `study_id` values brittle. Please change the query to `WHERE id = :study_id` and pass `study_id` as a parameter so the test behavior matches the function signature.

```suggestion
    # Adding requires the study to be in preparation,
    # but the current snapshot has no in-preparation studies.
    await expdb_test.execute(
        text("UPDATE study SET status = 'in_preparation' WHERE id = :study_id"),
        {"study_id": study_id},
    )
    return await py_api.post(
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 27, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 54.20%. Comparing base (e2fc422) to head (a548b20).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #295   +/-   ##
=======================================
  Coverage   54.20%   54.20%           
=======================================
  Files          38       38           
  Lines        1581     1581           
  Branches      137      137           
=======================================
  Hits          857      857           
  Misses        722      722           
  Partials        2        2           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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: 2

🧹 Nitpick comments (4)
tests/routers/openml/qualities_list_test.py (1)

162-167: Avoid mutating the baseline expected payload in-place.

At Line 162, mutating expected with .pop() makes the intent a bit harder to read. Keeping the original expected response immutable improves clarity.

♻️ Suggested refactor
-    deleted = expected["data_qualities_list"]["quality"].pop()
+    deleted = expected["data_qualities_list"]["quality"][-1]
+    expected_after_delete = {
+        "data_qualities_list": {
+            "quality": expected["data_qualities_list"]["quality"][:-1],
+        },
+    }
     await _remove_quality_from_database(quality_name=deleted, expdb_test=expdb_test)

     response = await py_api.get("/datasets/qualities/list")
     assert response.status_code == HTTPStatus.OK
-    assert expected == response.json()
+    assert expected_after_delete == response.json()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/routers/openml/qualities_list_test.py` around lines 162 - 167, The test
mutates the baseline `expected` payload by doing `deleted =
expected["data_qualities_list"]["quality"].pop()`, which makes the expected
response harder to reason about; instead, read the value without modifying
`expected` (e.g., pick the last element from
`expected["data_qualities_list"]["quality"]` or make a shallow copy of that
list) and pass that value to `_remove_quality_from_database(quality_name=...,
expdb_test=expdb_test)` so the subsequent `response.json()` can be compared
against the original immutable `expected`. Ensure you keep the identifier
`deleted` (or a similarly named variable) and leave `expected` unchanged before
the GET and assert.
tests/routers/openml/setups_tag_test.py (1)

32-34: Consider using parameterized SQL for consistency.

While this is test code and the values are hardcoded strings (not user input), using parameterized queries is a good habit that maintains consistency with production code patterns.

♻️ Optional: Use parameterized SQL
     await expdb_test.execute(
-        text("INSERT INTO setup_tag (id, tag, uploader) VALUES (1, 'existing_tag_123', 2);")
+        text("INSERT INTO setup_tag (id, tag, uploader) VALUES (:id, :tag, :uploader)"),
+        {"id": 1, "tag": "existing_tag_123", "uploader": 2},
     )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/routers/openml/setups_tag_test.py` around lines 32 - 34, Replace the
hardcoded SQL string in the test by using a parameterized query: change the
text("INSERT INTO setup_tag (id, tag, uploader) VALUES (1, 'existing_tag_123',
2);") passed to expdb_test.execute into a text() with named placeholders (e.g.,
:id, :tag, :uploader) and supply the parameter dict to expdb_test.execute so the
INSERT uses bound parameters instead of inlined values.
tests/routers/openml/study_post_test.py (1)

31-45: Consider extracting expected values that depend on test fixtures.

The hardcoded "creator": 2 ties the test to the assumption that ApiKey.SOME_USER maps to user ID 2. If the test user configuration changes, this test will fail with a confusing error.

♻️ Optional: Make creator expectation more explicit

Consider adding a comment or extracting to a constant:

# ApiKey.SOME_USER corresponds to user_id=2 in test fixtures
SOME_USER_ID = 2
# ...
"creator": SOME_USER_ID,

Or import/reference from the test user configuration if available.

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

In `@tests/routers/openml/study_post_test.py` around lines 31 - 45, The expected
dict hardcodes "creator": 2 which couples the test to a specific fixture
mapping; change the test to derive the creator id from the test fixture or
ApiKey mapping instead of using 2. Locate the expected dict named expected and
replace the literal for the "creator" key with a reference to the actual test
user id (e.g., a fixture value, a constant like SOME_USER_ID imported from your
test user config, or by resolving ApiKey.SOME_USER to its id) so the test
remains stable if fixture IDs change.
tests/routers/openml/study_attach_test.py (1)

46-46: Redundant database UPDATE before calling helper.

The _attach_tasks_to_study helper already executes the UPDATE statement to set the study status. The additional UPDATE on line 46 (and similarly on lines 62, 82) is redundant.

♻️ Remove redundant UPDATE calls
 async def test_attach_task_to_study_needs_owner(
     py_api: httpx.AsyncClient, expdb_test: AsyncConnection
 ) -> None:
-    await expdb_test.execute(text("UPDATE study SET status = 'in_preparation' WHERE id = 1"))
     response = await _attach_tasks_to_study(

Apply similar removal to lines 62 and 82.

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

In `@tests/routers/openml/study_attach_test.py` at line 46, Remove the redundant
direct UPDATE calls that set study.status to 'in_preparation' before invoking
the helper; the _attach_tasks_to_study test helper already performs that UPDATE,
so delete the await expdb_test.execute(text("UPDATE study SET status =
'in_preparation' WHERE id = 1")) occurrences (and the similar two duplicates) in
tests/routers/openml/study_attach_test.py so the test relies only on
_attach_tasks_to_study to change the study status.
🤖 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/routers/openml/flows_exists_test.py`:
- Around line 43-46: The tests patch the wrong import path for get_by_name;
update the mock.patch targets in all three tests
(test_flow_exists_calls_db_correctly, test_flow_exists_processes_found,
test_flow_exists_handles_flow_not_found) so they patch where
routers.openml.flows looks up the name (i.e., replace
"database.flows.get_by_name" with
"routers.openml.flows.database.flows.get_by_name" for the mocked_db patch in
each test) so the AsyncMock actually intercepts calls inside the flows.exists
handler.

In `@tests/routers/openml/study_attach_test.py`:
- Line 22: The UPDATE in tests/routers/openml/study_attach_test.py currently
hardcodes "WHERE id = 1" and ignores the helper's study_id parameter; change the
SQL to use a parameterized WHERE clause (e.g. "WHERE id = :study_id") and pass
the study_id when calling expdb_test.execute, so the UPDATE targets the provided
study_id (use a bound param dict like {"study_id": study_id} or equivalent with
text()).

---

Nitpick comments:
In `@tests/routers/openml/qualities_list_test.py`:
- Around line 162-167: The test mutates the baseline `expected` payload by doing
`deleted = expected["data_qualities_list"]["quality"].pop()`, which makes the
expected response harder to reason about; instead, read the value without
modifying `expected` (e.g., pick the last element from
`expected["data_qualities_list"]["quality"]` or make a shallow copy of that
list) and pass that value to `_remove_quality_from_database(quality_name=...,
expdb_test=expdb_test)` so the subsequent `response.json()` can be compared
against the original immutable `expected`. Ensure you keep the identifier
`deleted` (or a similarly named variable) and leave `expected` unchanged before
the GET and assert.

In `@tests/routers/openml/setups_tag_test.py`:
- Around line 32-34: Replace the hardcoded SQL string in the test by using a
parameterized query: change the text("INSERT INTO setup_tag (id, tag, uploader)
VALUES (1, 'existing_tag_123', 2);") passed to expdb_test.execute into a text()
with named placeholders (e.g., :id, :tag, :uploader) and supply the parameter
dict to expdb_test.execute so the INSERT uses bound parameters instead of
inlined values.

In `@tests/routers/openml/study_attach_test.py`:
- Line 46: Remove the redundant direct UPDATE calls that set study.status to
'in_preparation' before invoking the helper; the _attach_tasks_to_study test
helper already performs that UPDATE, so delete the await
expdb_test.execute(text("UPDATE study SET status = 'in_preparation' WHERE id =
1")) occurrences (and the similar two duplicates) in
tests/routers/openml/study_attach_test.py so the test relies only on
_attach_tasks_to_study to change the study status.

In `@tests/routers/openml/study_post_test.py`:
- Around line 31-45: The expected dict hardcodes "creator": 2 which couples the
test to a specific fixture mapping; change the test to derive the creator id
from the test fixture or ApiKey mapping instead of using 2. Locate the expected
dict named expected and replace the literal for the "creator" key with a
reference to the actual test user id (e.g., a fixture value, a constant like
SOME_USER_ID imported from your test user config, or by resolving
ApiKey.SOME_USER to its id) so the test remains stable if fixture IDs change.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 5b30d9d7-dba2-4a84-9d45-4fe73bc45928

📥 Commits

Reviewing files that changed from the base of the PR and between e2fc422 and 985aa26.

📒 Files selected for processing (14)
  • tests/routers/openml/datasets_qualities_test.py
  • tests/routers/openml/flows_exists_test.py
  • tests/routers/openml/flows_get_test.py
  • tests/routers/openml/qualities_list_test.py
  • tests/routers/openml/runs_trace_test.py
  • tests/routers/openml/setups_get_test.py
  • tests/routers/openml/setups_tag_test.py
  • tests/routers/openml/setups_untag_test.py
  • tests/routers/openml/study_attach_test.py
  • tests/routers/openml/study_get_test.py
  • tests/routers/openml/study_post_test.py
  • tests/routers/openml/task_get_test.py
  • tests/routers/openml/task_type_get_test.py
  • tests/routers/openml/task_type_list_test.py
💤 Files with no reviewable changes (4)
  • tests/routers/openml/task_type_get_test.py
  • tests/routers/openml/setups_untag_test.py
  • tests/routers/openml/flows_get_test.py
  • tests/routers/openml/datasets_qualities_test.py

@PGijsbers PGijsbers merged commit 99da4a0 into main Mar 27, 2026
9 checks passed
@PGijsbers PGijsbers deleted the organize-tests branch March 27, 2026 14:19
PGijsbers added a commit that referenced this pull request Mar 27, 2026
I accidentally only copied over some tests, instead of moving them in
#295. This fixes that.
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.

1 participant