91e75e620b
CI: cua-driver distro-compat matrix / Resolve release version (push) Waiting to run
CI: cua-driver distro-compat matrix / debian:12 (glibc 2.36) (push) Blocked by required conditions
CI: cua-driver distro-compat matrix / fedora:41 (glibc 2.40) (push) Blocked by required conditions
CI: cua-driver distro-compat matrix / rockylinux:9 (glibc 2.34) (push) Blocked by required conditions
CI: cua-driver distro-compat matrix / ubuntu:22.04 (glibc 2.35) (push) Blocked by required conditions
CI: cua-driver distro-compat matrix / ubuntu:24.04 (glibc 2.39) (push) Blocked by required conditions
CI: cua-driver distro-compat matrix / Distro compat summary (push) Blocked by required conditions
CI: Nix Linux Rust source / Nix / compositor build (push) Waiting to run
CI: Nix Linux Rust source / Nix / driver package (push) Waiting to run
CI: Nix Linux Rust source / Nix / Rust unit tests (push) Waiting to run
CI: Rust Linux unit / Rust Linux unit and compile (push) Waiting to run
CI: Rust Windows unit / Rust Windows unit and compile (push) Waiting to run
CI: SPDX Headers / Check SPDX headers (warn-only) (push) Waiting to run
CD: Docs MCP Server / build (linux/amd64) (push) Waiting to run
CD: Docs MCP Server / build (linux/arm64) (push) Waiting to run
CD: Docs MCP Server / merge (push) Blocked by required conditions
298 lines
9.8 KiB
Python
298 lines
9.8 KiB
Python
"""Tests for image command module."""
|
|
|
|
import argparse
|
|
from unittest.mock import patch
|
|
|
|
from cua_cli.commands import image
|
|
|
|
|
|
class TestRegisterParser:
|
|
"""Tests for register_parser function."""
|
|
|
|
def test_registers_image_command(self):
|
|
"""Test that image command is registered."""
|
|
parser = argparse.ArgumentParser()
|
|
subparsers = parser.add_subparsers()
|
|
|
|
image.register_parser(subparsers)
|
|
|
|
args = parser.parse_args(["image", "list"])
|
|
assert args.image_command == "list"
|
|
|
|
def test_registers_img_alias(self):
|
|
"""Test that img alias is registered."""
|
|
parser = argparse.ArgumentParser()
|
|
subparsers = parser.add_subparsers()
|
|
image.register_parser(subparsers)
|
|
|
|
args = parser.parse_args(["img", "list"])
|
|
assert args.image_command == "list"
|
|
|
|
def test_list_has_json_flag(self):
|
|
"""Test that list command has --json flag."""
|
|
parser = argparse.ArgumentParser()
|
|
subparsers = parser.add_subparsers()
|
|
image.register_parser(subparsers)
|
|
|
|
args = parser.parse_args(["image", "list", "--json"])
|
|
assert args.json is True
|
|
|
|
def test_list_has_local_flag(self):
|
|
"""Test that list command has --local flag."""
|
|
parser = argparse.ArgumentParser()
|
|
subparsers = parser.add_subparsers()
|
|
image.register_parser(subparsers)
|
|
|
|
args = parser.parse_args(["image", "list", "--local"])
|
|
assert args.local is True
|
|
|
|
def test_push_command(self):
|
|
"""Test that push command is registered."""
|
|
parser = argparse.ArgumentParser()
|
|
subparsers = parser.add_subparsers()
|
|
image.register_parser(subparsers)
|
|
|
|
args = parser.parse_args(["image", "push", "my-image"])
|
|
assert args.image_command == "push"
|
|
assert args.name == "my-image"
|
|
|
|
def test_pull_command(self):
|
|
"""Test that pull command is registered."""
|
|
parser = argparse.ArgumentParser()
|
|
subparsers = parser.add_subparsers()
|
|
image.register_parser(subparsers)
|
|
|
|
args = parser.parse_args(["image", "pull", "my-image"])
|
|
assert args.image_command == "pull"
|
|
assert args.name == "my-image"
|
|
|
|
def test_delete_command(self):
|
|
"""Test that delete command is registered."""
|
|
parser = argparse.ArgumentParser()
|
|
subparsers = parser.add_subparsers()
|
|
image.register_parser(subparsers)
|
|
|
|
args = parser.parse_args(["image", "delete", "my-image", "--force"])
|
|
assert args.image_command == "delete"
|
|
assert args.name == "my-image"
|
|
assert args.force is True
|
|
|
|
|
|
class TestExecute:
|
|
"""Tests for execute function."""
|
|
|
|
def test_dispatch_to_list(self, args_namespace):
|
|
"""Test dispatch to list command."""
|
|
args = args_namespace(
|
|
command="image",
|
|
image_command="list",
|
|
json=False,
|
|
local=False,
|
|
cloud=False,
|
|
)
|
|
|
|
with patch.object(image, "cmd_list", return_value=0) as mock_cmd:
|
|
result = image.execute(args)
|
|
|
|
mock_cmd.assert_called_once_with(args)
|
|
assert result == 0
|
|
|
|
def test_dispatch_to_push(self, args_namespace):
|
|
"""Test dispatch to push command."""
|
|
args = args_namespace(command="image", image_command="push", name="my-image")
|
|
|
|
with patch.object(image, "cmd_push", return_value=0) as mock_cmd:
|
|
image.execute(args)
|
|
|
|
mock_cmd.assert_called_once_with(args)
|
|
|
|
def test_dispatch_to_pull(self, args_namespace):
|
|
"""Test dispatch to pull command."""
|
|
args = args_namespace(command="image", image_command="pull", name="my-image")
|
|
|
|
with patch.object(image, "cmd_pull", return_value=0) as mock_cmd:
|
|
image.execute(args)
|
|
|
|
mock_cmd.assert_called_once_with(args)
|
|
|
|
def test_dispatch_to_delete(self, args_namespace):
|
|
"""Test dispatch to delete command."""
|
|
args = args_namespace(command="image", image_command="delete", name="my-image")
|
|
|
|
with patch.object(image, "cmd_delete", return_value=0) as mock_cmd:
|
|
image.execute(args)
|
|
|
|
mock_cmd.assert_called_once_with(args)
|
|
|
|
def test_unknown_command_returns_error(self, args_namespace):
|
|
"""Test that unknown command returns error."""
|
|
args = args_namespace(command="image", image_command=None)
|
|
|
|
with patch.object(image, "print_error"):
|
|
result = image.execute(args)
|
|
|
|
assert result == 1
|
|
|
|
|
|
class TestCmdList:
|
|
"""Tests for cmd_list function."""
|
|
|
|
def test_list_cloud_images(self, args_namespace, sample_cloud_images, mock_api_key):
|
|
"""Test listing cloud images."""
|
|
args = args_namespace(json=False, local=False, cloud=True)
|
|
|
|
with patch.object(image, "run_async") as mock_run:
|
|
mock_run.return_value = [
|
|
{
|
|
"name": "ubuntu-22.04",
|
|
"type": "qcow2",
|
|
"tag": "latest",
|
|
"size": "5.0 GB",
|
|
"status": "ready",
|
|
"created": "2024-01-10",
|
|
"source": "cloud",
|
|
}
|
|
]
|
|
with patch.object(image, "print_table") as mock_print:
|
|
result = image.cmd_list(args)
|
|
|
|
assert result == 0
|
|
mock_print.assert_called_once()
|
|
|
|
def test_list_local_images(self, args_namespace, tmp_path, monkeypatch):
|
|
"""Test listing local images delegates to local_image."""
|
|
args = args_namespace(json=False, local=True, cloud=False)
|
|
|
|
with patch("cua_cli.commands.local_image.cmd_local_list", return_value=0) as mock_local:
|
|
result = image.cmd_list(args)
|
|
|
|
assert result == 0
|
|
mock_local.assert_called_once_with(args)
|
|
|
|
def test_list_empty(self, args_namespace, tmp_path, monkeypatch):
|
|
"""Test listing when no local images exist."""
|
|
args = args_namespace(json=False, local=True, cloud=False)
|
|
|
|
with patch("cua_cli.commands.local_image.cmd_local_list", return_value=0) as mock_local:
|
|
result = image.cmd_list(args)
|
|
|
|
assert result == 0
|
|
mock_local.assert_called_once()
|
|
|
|
def test_list_json_output(self, args_namespace, mock_api_key):
|
|
"""Test JSON output format."""
|
|
args = args_namespace(json=True, local=False, cloud=True)
|
|
|
|
with patch.object(image, "run_async") as mock_run:
|
|
mock_run.return_value = [{"name": "test", "source": "cloud"}]
|
|
with patch.object(image, "print_json") as mock_print:
|
|
result = image.cmd_list(args)
|
|
|
|
assert result == 0
|
|
mock_print.assert_called_once()
|
|
|
|
|
|
class TestCmdPush:
|
|
"""Tests for cmd_push function."""
|
|
|
|
def test_push_success(self, args_namespace, temp_image_file, mock_api_key):
|
|
"""Test successful image push."""
|
|
args = args_namespace(
|
|
name="test-image",
|
|
tag="latest",
|
|
type="qcow2",
|
|
file=str(temp_image_file),
|
|
)
|
|
|
|
with patch.object(image, "run_async") as mock_run:
|
|
mock_run.return_value = 0
|
|
result = image.cmd_push(args)
|
|
|
|
assert result == 0
|
|
|
|
def test_push_file_not_found(self, args_namespace, mock_api_key):
|
|
"""Test push with nonexistent file."""
|
|
args = args_namespace(
|
|
name="test-image",
|
|
tag="latest",
|
|
type="qcow2",
|
|
file="/nonexistent/path",
|
|
)
|
|
|
|
with patch.object(image, "print_error") as mock_error:
|
|
result = image.cmd_push(args)
|
|
|
|
assert result == 1
|
|
mock_error.assert_called()
|
|
|
|
|
|
class TestCmdPull:
|
|
"""Tests for cmd_pull function."""
|
|
|
|
def test_pull_success(self, args_namespace, tmp_path, mock_api_key):
|
|
"""Test successful image pull."""
|
|
args = args_namespace(
|
|
name="test-image",
|
|
tag="latest",
|
|
output=str(tmp_path / "output.qcow2"),
|
|
)
|
|
|
|
with patch.object(image, "run_async") as mock_run:
|
|
mock_run.return_value = 0
|
|
result = image.cmd_pull(args)
|
|
|
|
assert result == 0
|
|
|
|
|
|
class TestCmdDelete:
|
|
"""Tests for cmd_delete function."""
|
|
|
|
def test_delete_with_force(self, args_namespace, mock_api_key):
|
|
"""Test delete with --force flag."""
|
|
args = args_namespace(name="test-image", tag="latest", force=True, local=False)
|
|
|
|
with patch.object(image, "run_async") as mock_run:
|
|
mock_run.return_value = 0
|
|
result = image.cmd_delete(args)
|
|
|
|
assert result == 0
|
|
|
|
def test_delete_without_force_prompts(self, args_namespace, mock_api_key):
|
|
"""Test delete without --force shows prompt."""
|
|
args = args_namespace(name="test-image", tag="latest", force=False, local=False)
|
|
|
|
with patch.object(image, "print_info") as mock_print:
|
|
result = image.cmd_delete(args)
|
|
|
|
assert result == 1
|
|
mock_print.assert_called()
|
|
|
|
def test_delete_local_delegates(self, args_namespace):
|
|
"""Test delete with --local delegates to local_image."""
|
|
args = args_namespace(name="test-image", tag="latest", force=True, local=True)
|
|
|
|
with patch("cua_cli.commands.local_image.cmd_local_delete", return_value=0) as mock_local:
|
|
result = image.cmd_delete(args)
|
|
|
|
assert result == 0
|
|
mock_local.assert_called_once_with(args)
|
|
|
|
|
|
class TestHelperFunctions:
|
|
"""Tests for helper functions."""
|
|
|
|
def test_format_date_valid(self):
|
|
"""Test formatting a valid ISO date."""
|
|
result = image._format_date("2024-01-15T10:30:00Z")
|
|
assert result == "2024-01-15"
|
|
|
|
def test_format_date_empty(self):
|
|
"""Test formatting empty string."""
|
|
result = image._format_date("")
|
|
assert result == "-"
|
|
|
|
def test_format_date_invalid(self):
|
|
"""Test formatting invalid date."""
|
|
result = image._format_date("not-a-date")
|
|
assert result == "not-a-date" # Falls back to first 10 chars
|