Skip to content

test: add unit tests for manage_packages tool and CLI#973

Merged
Scriptwonder merged 3 commits intoCoplayDev:betafrom
galofilip:add-manage-packages-tests
Mar 24, 2026
Merged

test: add unit tests for manage_packages tool and CLI#973
Scriptwonder merged 3 commits intoCoplayDev:betafrom
galofilip:add-manage-packages-tests

Conversation

@galofilip
Copy link
Copy Markdown
Contributor

@galofilip galofilip commented Mar 23, 2026

Description

What: Added unit tests for the manage_packages tool and CLI commands.

Why: The tool had no test coverage despite being a recently added core tool listed as Tier 1 in the roadmap.

Tests cover:

  • Action list completeness and no duplicates
  • Tool-level validation (unknown actions return errors, case insensitivity)
  • All CLI commands build the correct params dict (list, search, info, ping, status, add, remove, embed, resolve, list-registries, add-registry, remove-registry)

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Refactoring (no functional changes)
  • Test update

Changes Made

  • Added Server/tests/test_manage_packages.py with 24 unit tests across 4 test classes:
    • TestActionLists — verifies the ALL_ACTIONS list is complete and has no duplicates
    • TestManagePackagesToolValidation — verifies the Python tool rejects invalid actions without connecting to Unity
    • TestPackagesQueryCLICommands — verifies query commands (list, search, info, ping, status) build correct params
    • TestPackagesInstallRemoveCLICommands — verifies install/remove commands (add, remove, embed, resolve) build correct params
    • TestRegistryCLICommands — verifies registry commands (list-registries, add-registry, remove-registry) build correct params

Testing/Screenshots/Recordings

All 24 tests pass locally: 24 passed in 4.58s

No Unity connection required — tests run entirely in Python by mocking the transport layer.

Documentation Updates

  • I have added/removed/modified tools or resources
  • If yes, I have updated all documentation files using:
    • The LLM prompt at tools/UPDATE_DOCS_PROMPT.md (recommended)
    • Manual updates following the guide at tools/UPDATE_DOCS.md

Related Issues

N/A

Additional Notes

Tests follow the same structure and conventions as the existing test_manage_animation.py.

Summary by Sourcery

Add comprehensive unit test coverage for the manage_packages tool and its CLI commands to validate supported actions and parameter construction.

Tests:

  • Add tests to ensure ALL_ACTIONS is non-empty, contains no duplicates, and includes all expected package and registry operations.
  • Add tool-level tests to verify invalid actions return errors and that action matching is case-insensitive without requiring a Unity connection.
  • Add CLI tests to confirm all package query, install/remove, and registry commands construct the correct parameter dictionaries passed to run_command.

Summary by CodeRabbit

  • Tests
    • Added comprehensive test coverage for the package management tool and CLI: verifies available actions set and structural invariants, checks error handling for unknown actions, ensures case-insensitive action matching, and confirms CLI commands construct and pass expected parameters (including optional fields and multi-valued options) to the command runner.

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai bot commented Mar 23, 2026

Reviewer's Guide

Adds comprehensive unit tests for the manage_packages tool and its CLI commands, covering action list integrity, tool-level action validation, and parameter construction for all package and registry subcommands without requiring a Unity connection.

File-Level Changes

Change Details Files
Add unit tests for manage_packages tool action list integrity and validation behavior.
  • Introduce tests ensuring ALL_ACTIONS is non-empty, has no duplicates, and includes all expected query/install/registry actions.
  • Add tests verifying manage_packages rejects unknown actions with clear error messages that include valid actions.
  • Add test ensuring manage_packages action matching is case-insensitive by patching the internal _send_packages_command coroutine.
Server/tests/test_manage_packages.py
Add CLI-level tests ensuring all packages subcommands build the correct params dict passed to run_command.
  • Add helper function to extract params from mocked run_command invocations.
  • Add tests for query subcommands (list, search, info, ping, status) asserting correct action names and optional arguments like job_id and query.
  • Add tests for install/remove subcommands (add, remove, embed, resolve) asserting correct action names, package strings, and flags such as force.
  • Add tests for registry subcommands (list-registries, add-registry, remove-registry) asserting correct action names and fields including name, url, and scopes, including multi-scope handling.
Server/tests/test_manage_packages.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 23, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7905721f-8ee5-4d76-99ed-5032de8b6361

📥 Commits

Reviewing files that changed from the base of the PR and between 890be2d and 2dd83df.

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

📝 Walkthrough

Walkthrough

Added a new test module Server/tests/test_manage_packages.py that exercises the manage_packages tool and packages Click CLI group: it checks ALL_ACTIONS invariants, handles unknown and case-insensitive actions, and verifies CLI commands construct correct run_command parameter payloads via mocked config and runner.

Changes

Cohort / File(s) Summary
New test module
Server/tests/test_manage_packages.py
Introduces a ~303-line pytest suite validating: ALL_ACTIONS invariants (non-empty, no duplicates, expected categories); manage_packages behavior for unknown actions and case-insensitive action normalization; CLI packages subcommand tests (query, install/remove, registry commands) asserting run_command is invoked with correctly constructed parameter dictionaries; uses fixtures for CliRunner, mocked get_config, and mocked run_command responses.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 I nibbled through tests with nimble paws,

Assertions lined up like tidy little laws,
Actions counted, casing made right,
Commands mocked and parameters tight,
A hop, a chirp — the suite takes flight!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.57% 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 title clearly and accurately describes the main change: adding unit tests for the manage_packages tool and CLI, which is the sole focus of this changeset.
Description check ✅ Passed The description fully addresses the template with a comprehensive explanation, correct type of change selection, detailed changes made, test results, and follows repository conventions.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit 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 _get_params, consider accessing the params argument by name (e.g., mock_run.call_args.kwargs['params']) instead of positional index [1] to make the tests more robust against changes in the run_command call signature.
  • The repeated nested patch('cli.commands.packages.get_config', ...) / patch('cli.commands.packages.run_command', ...) blocks in the CLI tests could be refactored into a reusable helper or fixture to reduce duplication and make the tests easier to maintain.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `_get_params`, consider accessing the `params` argument by name (e.g., `mock_run.call_args.kwargs['params']`) instead of positional index `[1]` to make the tests more robust against changes in the `run_command` call signature.
- The repeated nested `patch('cli.commands.packages.get_config', ...)` / `patch('cli.commands.packages.run_command', ...)` blocks in the CLI tests could be refactored into a reusable helper or fixture to reduce duplication and make the tests easier to maintain.

## Individual Comments

### Comment 1
<location path="Server/tests/test_manage_packages.py" line_range="71-79" />
<code_context>
+class TestManagePackagesToolValidation:
+    """Test action validation in the manage_packages tool function."""
+
+    def test_unknown_action_returns_error(self):
+        from services.tools.manage_packages import manage_packages
+
+        ctx = MagicMock()
+        ctx.get_state = AsyncMock(return_value=None)
+
+        result = asyncio.run(manage_packages(ctx, action="invalid_action"))
+        assert result["success"] is False
+        assert "Unknown action" in result["message"]
+
+    def test_unknown_action_lists_valid_actions(self):
</code_context>
<issue_to_address>
**suggestion (testing):** Consider asserting that no Unity-related calls are made for an unknown action.

This test only checks the error payload. Since a key requirement is rejecting invalid actions *without* contacting Unity, add an assertion that no Unity calls are made. For example, patch `services.tools.manage_packages._send_packages_command` (and/or `ctx.get_state`) and assert they are never called/awaited, so the test also validates the fail-fast behavior at the transport boundary.

```suggestion
    def test_unknown_action_returns_error(self):
        from services.tools.manage_packages import manage_packages
        from unittest.mock import patch

        ctx = MagicMock()
        ctx.get_state = AsyncMock(return_value=None)

        with patch("services.tools.manage_packages._send_packages_command") as send_packages_command:
            result = asyncio.run(manage_packages(ctx, action="invalid_action"))

        assert result["success"] is False
        assert "Unknown action" in result["message"]
        # Fail-fast: do not talk to Unity or even attempt to fetch state
        send_packages_command.assert_not_called()
        ctx.get_state.assert_not_awaited()
```
</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.

Comment on lines +71 to +79
def test_unknown_action_returns_error(self):
from services.tools.manage_packages import manage_packages

ctx = MagicMock()
ctx.get_state = AsyncMock(return_value=None)

result = asyncio.run(manage_packages(ctx, action="invalid_action"))
assert result["success"] is False
assert "Unknown action" in result["message"]
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.

suggestion (testing): Consider asserting that no Unity-related calls are made for an unknown action.

This test only checks the error payload. Since a key requirement is rejecting invalid actions without contacting Unity, add an assertion that no Unity calls are made. For example, patch services.tools.manage_packages._send_packages_command (and/or ctx.get_state) and assert they are never called/awaited, so the test also validates the fail-fast behavior at the transport boundary.

Suggested change
def test_unknown_action_returns_error(self):
from services.tools.manage_packages import manage_packages
ctx = MagicMock()
ctx.get_state = AsyncMock(return_value=None)
result = asyncio.run(manage_packages(ctx, action="invalid_action"))
assert result["success"] is False
assert "Unknown action" in result["message"]
def test_unknown_action_returns_error(self):
from services.tools.manage_packages import manage_packages
from unittest.mock import patch
ctx = MagicMock()
ctx.get_state = AsyncMock(return_value=None)
with patch("services.tools.manage_packages._send_packages_command") as send_packages_command:
result = asyncio.run(manage_packages(ctx, action="invalid_action"))
assert result["success"] is False
assert "Unknown action" in result["message"]
# Fail-fast: do not talk to Unity or even attempt to fetch state
send_packages_command.assert_not_called()
ctx.get_state.assert_not_awaited()

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

🧹 Nitpick comments (1)
Server/tests/test_manage_packages.py (1)

118-126: Consider verifying CLI exit code for test robustness.

The tests verify that run_command is called with correct params, but don't check the CLI's exit code. If the command fails silently or raises an exception (caught by CliRunner by default), tests could still pass.

Proposed enhancement with exit code verification
     def test_list_builds_correct_params(self, runner, mock_config, mock_success):
         with patch("cli.commands.packages.get_config", return_value=mock_config):
             with patch("cli.commands.packages.run_command", return_value=mock_success) as mock_run:
-                runner.invoke(packages, ["list"])
+                result = runner.invoke(packages, ["list"], catch_exceptions=False)
 
+                assert result.exit_code == 0
                 mock_run.assert_called_once()
                 params = _get_params(mock_run)
                 assert params["action"] == "list_packages"

Consider applying a similar pattern to other CLI tests for consistent robustness.

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

In `@Server/tests/test_manage_packages.py` around lines 118 - 126, Update the
test_list_builds_correct_params to capture and assert the CLI exit code: call
runner.invoke(packages, ["list"]) and assign its return to a variable (e.g.,
result), then assert result.exit_code == 0 (or the expected code) in addition to
the existing mock_run assertions; make this change in the
test_list_builds_correct_params function and keep the existing checks using
_get_params(mock_run) and params["action"] == "list_packages".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Server/tests/test_manage_packages.py`:
- Around line 87-90: The test's assertion is too permissive using an OR; update
the assertion in tests/test_manage_packages.py so it verifies the error message
contains both the "Valid actions" text and a known action (e.g., "add_package")
or, even better, compare against the exact expected string using ALL_ACTIONS and
the manage_packages(action=...) format; locate the manage_packages call and
ALL_ACTIONS reference in this test and replace the current or-check with either
an and-check (assert "Valid actions" in result["message"] and "add_package" in
result["message"]) or an exact equality using f"Unknown action 'bogus'. Valid
actions: {', '.join(ALL_ACTIONS)}".

---

Nitpick comments:
In `@Server/tests/test_manage_packages.py`:
- Around line 118-126: Update the test_list_builds_correct_params to capture and
assert the CLI exit code: call runner.invoke(packages, ["list"]) and assign its
return to a variable (e.g., result), then assert result.exit_code == 0 (or the
expected code) in addition to the existing mock_run assertions; make this change
in the test_list_builds_correct_params function and keep the existing checks
using _get_params(mock_run) and params["action"] == "list_packages".

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 00018e3c-46c2-45fe-9ff6-fd3f62df901b

📥 Commits

Reviewing files that changed from the base of the PR and between ca28802 and ce7893a.

📒 Files selected for processing (1)
  • Server/tests/test_manage_packages.py

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

♻️ Duplicate comments (1)
Server/tests/test_manage_packages.py (1)

110-120: ⚠️ Potential issue | 🟡 Minor

Strengthen the unknown-action message assertion.

Line 119 only checks "Valid actions"; this can pass even if the valid-action list is incomplete or missing known entries. Assert the full expected string (or at least also assert a known action token).

Suggested test tightening
     result = asyncio.run(manage_packages(ctx, action="bogus"))
     assert result["success"] is False
-    assert "Valid actions" in result["message"]
+    expected = f"Unknown action 'bogus'. Valid actions: {', '.join(ALL_ACTIONS)}"
+    assert result["message"] == expected
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Server/tests/test_manage_packages.py` around lines 110 - 120, Update the
test_unknown_action_lists_valid_actions assertion to ensure the unknown-action
error message includes a known valid action token (instead of only checking for
the generic "Valid actions"); in the test function
(test_unknown_action_lists_valid_actions) call manage_packages as before but add
an assertion that result["message"] contains a specific expected action name
from manage_packages (e.g., "install" or whichever action string is defined in
the manage_packages implementation) so the test fails if the valid-action list
is incomplete or missing entries.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Server/tests/test_manage_packages.py`:
- Around line 142-149: The test should verify that manage_packages lowercases
the action before dispatching to _send_packages_command: after calling
manage_packages(ctx, action="LIST_PACKAGES") inspect the AsyncMock mock_send's
awaited call (mock_send.assert_awaited() and inspect mock_send.call_args) and
assert that the sent payload or argument includes the normalized string
"list_packages" (or that the action arg equals "list_packages"); update the
assertion to check mock_send.call_args/kwargs rather than only result["success"]
to prove case-insensitive normalization in the manage_packages ->
_send_packages_command flow.

---

Duplicate comments:
In `@Server/tests/test_manage_packages.py`:
- Around line 110-120: Update the test_unknown_action_lists_valid_actions
assertion to ensure the unknown-action error message includes a known valid
action token (instead of only checking for the generic "Valid actions"); in the
test function (test_unknown_action_lists_valid_actions) call manage_packages as
before but add an assertion that result["message"] contains a specific expected
action name from manage_packages (e.g., "install" or whichever action string is
defined in the manage_packages implementation) so the test fails if the
valid-action list is incomplete or missing entries.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0d217b18-182b-4016-b345-e0c6ac329104

📥 Commits

Reviewing files that changed from the base of the PR and between ce7893a and 890be2d.

📒 Files selected for processing (1)
  • Server/tests/test_manage_packages.py

@Scriptwonder Scriptwonder merged commit 37129a6 into CoplayDev:beta Mar 24, 2026
2 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