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
3 changes: 1 addition & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
import pytest
from click.testing import CliRunner
from faker import Faker
from httpx import Headers

from th_cli.api_lib_autogen import models as api_models
from th_cli.api_lib_autogen.api_client import ApiClient, AsyncApis, SyncApis
Expand Down Expand Up @@ -447,7 +446,7 @@ def sample_test_runner_status() -> api_models.TestRunnerStatus:
@pytest.fixture
def mock_unexpected_response() -> UnexpectedResponse:
"""Create a mock UnexpectedResponse exception."""
return UnexpectedResponse(status_code=404, content=b"Not Found", headers=Headers())
return UnexpectedResponse(status_code=404, content=b"Not Found")


@pytest.fixture
Expand Down
86 changes: 75 additions & 11 deletions tests/test_test_run_execution.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def test_test_run_execution_success_all(
assert "Test Run 1" in result.output
assert "Test Run 2" in result.output
assert "PASSED" in result.output
api.assert_called_once_with(skip=None, limit=None, sort_order="desc", project_id=None)
api.assert_called_once_with(skip=None, limit=None, sort_order="desc", project_id=None, archived=False)
mock_api_client.close.assert_called_once()

def test_test_run_execution_success_specific_id(
Expand Down Expand Up @@ -107,7 +107,7 @@ def test_test_run_execution_success_with_pagination(
# Assert
assert result.exit_code == 0
assert "Test Run 3" in result.output
api.assert_called_once_with(skip=10, limit=5, sort_order="desc", project_id=None)
api.assert_called_once_with(skip=10, limit=5, sort_order="desc", project_id=None, archived=False)

def test_test_run_execution_success_json_output(
self,
Expand Down Expand Up @@ -316,7 +316,7 @@ def test_test_run_execution_pagination_parameters(

# Assert
assert result.exit_code == 0
api.assert_called_once_with(skip=skip, limit=limit, sort_order="desc", project_id=None)
api.assert_called_once_with(skip=skip, limit=limit, sort_order="desc", project_id=None, archived=False)

def test_test_run_execution_error_display(
self,
Expand Down Expand Up @@ -742,7 +742,7 @@ def test_test_run_execution_sort_parameter_asc(
# Assert
assert result.exit_code == 0
assert "Old Test Run" in result.output
api.assert_called_once_with(skip=None, limit=None, sort_order="asc", project_id=None)
api.assert_called_once_with(skip=None, limit=None, sort_order="asc", project_id=None, archived=False)
mock_api_client.close.assert_called_once()

def test_test_run_execution_sort_parameter_desc_default(
Expand Down Expand Up @@ -770,7 +770,7 @@ def test_test_run_execution_sort_parameter_desc_default(
assert result.exit_code == 0
assert "New Test Run" in result.output
assert "Old Test Run" in result.output
api.assert_called_once_with(skip=None, limit=None, sort_order="desc", project_id=None)
api.assert_called_once_with(skip=None, limit=None, sort_order="desc", project_id=None, archived=False)
mock_api_client.close.assert_called_once()

def test_test_run_execution_sort_parameter_explicit_desc(
Expand Down Expand Up @@ -798,7 +798,7 @@ def test_test_run_execution_sort_parameter_explicit_desc(
assert result.exit_code == 0
assert "New Test Run" in result.output
assert "Old Test Run" in result.output
api.assert_called_once_with(skip=None, limit=None, sort_order="desc", project_id=None)
api.assert_called_once_with(skip=None, limit=None, sort_order="desc", project_id=None, archived=False)
mock_api_client.close.assert_called_once()

def test_test_run_execution_all_flag(
Expand Down Expand Up @@ -826,7 +826,7 @@ def test_test_run_execution_all_flag(
# Assert
assert result.exit_code == 0
# When --all is used, limit should be set to 0
api.assert_called_once_with(skip=None, limit=0, sort_order="desc", project_id=None)
api.assert_called_once_with(skip=None, limit=0, sort_order="desc", project_id=None, archived=False)
mock_api_client.close.assert_called_once()

def test_test_run_execution_all_with_limit_fails(
Expand Down Expand Up @@ -885,7 +885,7 @@ def test_test_run_execution_with_project_id(
# Assert
assert result.exit_code == 0
assert "Project 5 Test Run" in result.output
api.assert_called_once_with(skip=None, limit=None, sort_order="desc", project_id=5)
api.assert_called_once_with(skip=None, limit=None, sort_order="desc", project_id=5, archived=False)
mock_api_client.close.assert_called_once()

def test_test_run_execution_with_project_id_short_form(
Expand All @@ -909,7 +909,7 @@ def test_test_run_execution_with_project_id_short_form(
# Assert
assert result.exit_code == 0
assert "Project 10 Test Run" in result.output
api.assert_called_once_with(skip=None, limit=None, sort_order="desc", project_id=10)
api.assert_called_once_with(skip=None, limit=None, sort_order="desc", project_id=10, archived=False)
mock_api_client.close.assert_called_once()

def test_test_run_execution_with_project_id_and_pagination(
Expand All @@ -933,7 +933,7 @@ def test_test_run_execution_with_project_id_and_pagination(
# Assert
assert result.exit_code == 0
assert "Filtered Paginated Test Run" in result.output
api.assert_called_once_with(skip=5, limit=10, sort_order="desc", project_id=7)
api.assert_called_once_with(skip=5, limit=10, sort_order="desc", project_id=7, archived=False)
mock_api_client.close.assert_called_once()

def test_test_run_execution_with_project_id_and_sort(
Expand All @@ -954,7 +954,7 @@ def test_test_run_execution_with_project_id_and_sort(

# Assert
assert result.exit_code == 0
api.assert_called_once_with(skip=None, limit=None, sort_order="asc", project_id=3)
api.assert_called_once_with(skip=None, limit=None, sort_order="asc", project_id=3, archived=False)
mock_api_client.close.assert_called_once()

def test_test_run_execution_project_id_with_log_fails(
Expand All @@ -969,3 +969,67 @@ def test_test_run_execution_project_id_with_log_fails(
assert result.exit_code != 0
assert "--project-id" in result.output
assert "not applicable" in result.output or "Error" in result.output

def test_test_run_execution_archived_flag(
self, cli_runner: CliRunner, mock_sync_apis: Mock, mock_api_client: Mock
) -> None:
"""Test that --archived filters for archived test run executions only."""
# Arrange
test_executions = [
api_models.TestRunExecution(
id=1, title="Archived Run", state=api_models.TestStateEnum.passed, project_id=1
),
]
api = mock_sync_apis.test_run_executions_api.read_test_run_executions_api_v1_test_run_executions__get
api.return_value = test_executions

with patch("th_cli.commands.test_run_execution.get_client", return_value=mock_api_client):
with patch("th_cli.commands.test_run_execution.SyncApis", return_value=mock_sync_apis):
# Act
result = cli_runner.invoke(test_run_execution, ["--archived"])

# Assert
assert result.exit_code == 0
assert "Archived Run" in result.output
assert "Archived: yes" in result.output
api.assert_called_once_with(skip=None, limit=None, sort_order="desc", project_id=None, archived=True)
mock_api_client.close.assert_called_once()

def test_test_run_execution_archived_flag_with_project_id(
self, cli_runner: CliRunner, mock_sync_apis: Mock, mock_api_client: Mock
) -> None:
"""Test that --archived can be combined with --project-id."""
# Arrange
api = mock_sync_apis.test_run_executions_api.read_test_run_executions_api_v1_test_run_executions__get
api.return_value = []

with patch("th_cli.commands.test_run_execution.get_client", return_value=mock_api_client):
with patch("th_cli.commands.test_run_execution.SyncApis", return_value=mock_sync_apis):
# Act
result = cli_runner.invoke(test_run_execution, ["--archived", "--project-id", "5"])

# Assert
assert result.exit_code == 0
api.assert_called_once_with(skip=None, limit=None, sort_order="desc", project_id=5, archived=True)

def test_test_run_execution_archived_with_id_fails(
self,
cli_runner: CliRunner,
) -> None:
"""Test that --archived cannot be used with --id."""
# Act
result = cli_runner.invoke(test_run_execution, ["--id", "123", "--archived"])

# Assert
assert result.exit_code != 0
assert "--archived" in result.output
assert "not applicable" in result.output or "Error" in result.output

def test_test_run_execution_help_shows_archived_option(self, cli_runner: CliRunner) -> None:
"""Test that the help message includes the --archived option."""
# Act
result = cli_runner.invoke(test_run_execution, ["--help"])

# Assert
assert result.exit_code == 0
assert "--archived" in result.output
118 changes: 118 additions & 0 deletions tests/test_test_run_execution_archive_unarchive.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#
# 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 archive` and `test-run-execution unarchive` commands."""

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 TestArchiveTestRunExecutionCommand:
"""Test cases for the `test-run-execution archive` command."""

def test_archive_success(self, cli_runner: CliRunner, mock_sync_apis: Mock) -> None:
"""Test successful archiving."""
api = mock_sync_apis.test_run_executions_api
api.archive_api_v1_test_run_executions__id__archive_post.return_value = None

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

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

def test_archive_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.archive_api_v1_test_run_executions__id__archive_post.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, ["archive", "--id", "1"])

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

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

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

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

assert result.exit_code == 0
assert "archive" in result.output
assert "--id" in result.output


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

def test_unarchive_success(self, cli_runner: CliRunner, mock_sync_apis: Mock) -> None:
"""Test successful unarchiving."""
api = mock_sync_apis.test_run_executions_api
api.unarchive_api_v1_test_run_executions__id__unarchive_post.return_value = None

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

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

def test_unarchive_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.unarchive_api_v1_test_run_executions__id__unarchive_post.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, ["unarchive", "--id", "1"])

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

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

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

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

assert result.exit_code == 0
assert "unarchive" in result.output
assert "--id" in result.output
Loading
Loading