Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions tests/test_test_run_execution_delete.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#
# Copyright (c) 2026 Project CHIP Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Tests for the `test-run-execution delete` command."""

from unittest.mock import Mock, patch

import pytest
from click.testing import CliRunner

from th_cli.api_lib_autogen.exceptions import UnexpectedResponse
from th_cli.commands.test_run_execution import test_run_execution


@pytest.mark.unit
@pytest.mark.cli
class TestDeleteTestRunExecutionCommand:
"""Test cases for the `test-run-execution delete` command."""

def test_delete_success_with_yes_flag(self, cli_runner: CliRunner, mock_sync_apis: Mock) -> None:
"""Test successful deletion with --yes flag skips confirmation."""
api = mock_sync_apis.test_run_executions_api
api.remove_test_run_execution_api_v1_test_run_executions__id__delete.return_value = None

with patch("th_cli.commands.test_run_execution.SyncApis", return_value=mock_sync_apis):
result = cli_runner.invoke(test_run_execution, ["delete", "--id", "1", "--yes"])

assert result.exit_code == 0
assert "Test run execution 1 was deleted." in result.output
api.remove_test_run_execution_api_v1_test_run_executions__id__delete.assert_called_once_with(id=1)

def test_delete_success_with_confirmation(self, cli_runner: CliRunner, mock_sync_apis: Mock) -> None:
"""Test successful deletion when the user confirms the prompt."""
api = mock_sync_apis.test_run_executions_api
api.remove_test_run_execution_api_v1_test_run_executions__id__delete.return_value = None

with patch("th_cli.commands.test_run_execution.SyncApis", return_value=mock_sync_apis):
result = cli_runner.invoke(test_run_execution, ["delete", "--id", "1"], input="y\n")

assert result.exit_code == 0
assert "Test run execution 1 was deleted." in result.output

def test_delete_abort_on_no_confirmation(self, cli_runner: CliRunner, mock_sync_apis: Mock) -> None:
"""Test deletion is aborted when the user declines confirmation."""
with patch("th_cli.commands.test_run_execution.SyncApis", return_value=mock_sync_apis):
result = cli_runner.invoke(test_run_execution, ["delete", "--id", "1"], input="n\n")

assert result.exit_code == 0 # Aborted, not an error
assert "Operation cancelled." in result.output
mock_sync_apis.test_run_executions_api.remove_test_run_execution_api_v1_test_run_executions__id__delete.assert_not_called() # noqa: E501

def test_delete_api_error(self, cli_runner: CliRunner, mock_sync_apis: Mock) -> None:
"""Test that an API error is surfaced to the user."""
api = mock_sync_apis.test_run_executions_api
api.remove_test_run_execution_api_v1_test_run_executions__id__delete.side_effect = UnexpectedResponse(
status_code=404,
content=b"Not Found",
)

with patch("th_cli.commands.test_run_execution.SyncApis", return_value=mock_sync_apis):
result = cli_runner.invoke(test_run_execution, ["delete", "--id", "1", "--yes"])

assert result.exit_code == 1
assert "Error: Failed to delete test run execution ID '1' (Status: 404) - Not Found" in result.output

def test_delete_requires_id(self, cli_runner: CliRunner) -> None:
"""The --id parameter is required."""
result = cli_runner.invoke(test_run_execution, ["delete"])

assert result.exit_code != 0
assert "Missing option" in result.output or "--id" in result.output

def test_delete_help_message(self, cli_runner: CliRunner) -> None:
"""Test the help message for the delete command."""
result = cli_runner.invoke(test_run_execution, ["delete", "--help"])

assert result.exit_code == 0
assert "delete" in result.output
assert "--id" in result.output
assert "--yes" in result.output
53 changes: 52 additions & 1 deletion th_cli/commands/test_run_execution.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,15 @@
from th_cli.api_lib_autogen.api_client import SyncApis
from th_cli.api_lib_autogen.exceptions import UnexpectedResponse
from th_cli.client import get_client
from th_cli.colorize import colorize_cmd_help, colorize_header, colorize_help, colorize_state, italic
from th_cli.colorize import (
colorize_cmd_help,
colorize_error,
colorize_header,
colorize_help,
colorize_state,
colorize_success,
italic,
)
from th_cli.exceptions import CLIError, handle_api_error
from th_cli.utils import __print_json

Expand Down Expand Up @@ -248,6 +256,49 @@ def pics_export(id: int, output_file: str) -> None:
raise # Re-raise CLI Errors as-is


@test_run_execution.command(
name="delete",
short_help=colorize_help("Delete a test run execution"),
help=colorize_cmd_help("delete", "Delete a test run execution"),
)
@click.option(
"--id",
"-i",
required=True,
type=int,
help=colorize_help("Test Run Execution ID to delete"),
)
@click.option(
"--yes",
"-y",
is_flag=True,
help=colorize_help("Delete the test run execution without confirmation"),
)
def delete(id: int, yes: bool) -> None:
"""Delete a test run execution"""
if not yes:
if not click.confirm(colorize_error("Are you sure you want to delete the test run execution?")):
click.echo("Operation cancelled.")
return

try:
with closing(get_client()) as client:
sync_apis = SyncApis(client)
__delete_test_run_execution(sync_apis, id)

except CLIError:
raise # Re-raise CLI Errors as-is


def __delete_test_run_execution(sync_apis: SyncApis, id: int) -> None:
try:
test_run_execution_api = sync_apis.test_run_executions_api
test_run_execution_api.remove_test_run_execution_api_v1_test_run_executions__id__delete(id=id)
click.echo(colorize_success(f"Test run execution {id} was deleted."))
except UnexpectedResponse as e:
handle_api_error(e, f"delete test run execution ID '{id}'")


def __test_run_execution_by_id(sync_apis: SyncApis, id: int, json: bool) -> None:
try:
test_run_execution_api = sync_apis.test_run_executions_api
Expand Down
Loading