#!/usr/bin/env python3 import pytest from unittest.mock import Mock, patch from datetime import datetime, timedelta from kumacli.client import KumaClient class TestKumaClient: def test_parse_duration_minutes(self): """Test parsing duration in minutes""" client = KumaClient("http://test.com") assert client.parse_duration("90m") == 5400 # 90 * 60 assert client.parse_duration("1m") == 60 assert client.parse_duration("120m") == 7200 def test_parse_duration_hours(self): """Test parsing duration in hours""" client = KumaClient("http://test.com") assert client.parse_duration("1h") == 3600 # 1 * 3600 assert client.parse_duration("2h") == 7200 assert client.parse_duration("24h") == 86400 def test_parse_duration_seconds(self): """Test parsing duration in seconds""" client = KumaClient("http://test.com") assert client.parse_duration("3600s") == 3600 assert client.parse_duration("60s") == 60 assert client.parse_duration("1s") == 1 def test_parse_duration_default(self): """Test parsing duration with default value""" client = KumaClient("http://test.com") assert client.parse_duration(None) == 5400 # Default 90 minutes assert client.parse_duration("") == 5400 def test_parse_duration_invalid(self): """Test parsing invalid duration format""" client = KumaClient("http://test.com") with pytest.raises(ValueError, match="Invalid duration format"): client.parse_duration("invalid") with pytest.raises(ValueError, match="Invalid duration format"): client.parse_duration("90x") with pytest.raises(ValueError, match="Invalid duration format"): client.parse_duration("90") def test_parse_start_time_none(self): """Test parsing start time with None (current time)""" client = KumaClient("http://test.com") before = datetime.utcnow() result = client.parse_start_time(None) after = datetime.utcnow() assert before <= result <= after def test_parse_start_time_iso_format(self): """Test parsing ISO format start time""" client = KumaClient("http://test.com") # Test ISO format with Z result = client.parse_start_time("2023-12-25T10:30:00Z") expected = datetime(2023, 12, 25, 10, 30, 0) assert result == expected # Test ISO format with timezone result = client.parse_start_time("2023-12-25T10:30:00+00:00") assert result == expected def test_parse_start_time_common_formats(self): """Test parsing common date/time formats""" client = KumaClient("http://test.com") # Full datetime result = client.parse_start_time("2023-12-25 10:30:00") expected = datetime(2023, 12, 25, 10, 30, 0) assert result == expected # Date and hour:minute result = client.parse_start_time("2023-12-25 10:30") expected = datetime(2023, 12, 25, 10, 30, 0) assert result == expected # Date only result = client.parse_start_time("2023-12-25") expected = datetime(2023, 12, 25, 0, 0, 0) assert result == expected def test_parse_start_time_invalid(self): """Test parsing invalid start time format""" client = KumaClient("http://test.com") with pytest.raises(ValueError, match="Invalid start time format"): client.parse_start_time("invalid-date") with pytest.raises(ValueError, match="Invalid start time format"): client.parse_start_time("2023-13-45") def test_find_monitors_by_pattern_success(self): """Test finding monitors by pattern successfully""" client = KumaClient("http://test.com") client.api = Mock() mock_monitors = [ {"id": 1, "name": "Web Server"}, {"id": 2, "name": "API Server"}, {"id": 3, "name": "Database"}, {"id": 4, "name": "Web Frontend"}, ] client.api.get_monitors.return_value = mock_monitors # Test exact match result = client.find_monitors_by_pattern(["Web Server"]) assert len(result) == 1 assert result[0]["name"] == "Web Server" # Test wildcard pattern result = client.find_monitors_by_pattern(["Web*"]) assert len(result) == 2 names = [m["name"] for m in result] assert "Web Server" in names assert "Web Frontend" in names def test_find_monitors_by_pattern_case_insensitive(self): """Test finding monitors by pattern is case insensitive""" client = KumaClient("http://test.com") client.api = Mock() mock_monitors = [ {"id": 1, "name": "Web Server"}, {"id": 2, "name": "API Server"}, ] client.api.get_monitors.return_value = mock_monitors # Test case insensitive matching result = client.find_monitors_by_pattern(["web*"]) assert len(result) == 1 assert result[0]["name"] == "Web Server" def test_find_monitors_by_pattern_no_matches(self): """Test finding monitors with no matches""" client = KumaClient("http://test.com") client.api = Mock() mock_monitors = [{"id": 1, "name": "Web Server"}] client.api.get_monitors.return_value = mock_monitors result = client.find_monitors_by_pattern(["Database*"]) assert len(result) == 0 def test_find_monitors_by_pattern_duplicates(self): """Test finding monitors removes duplicates""" client = KumaClient("http://test.com") client.api = Mock() mock_monitors = [{"id": 1, "name": "Web Server"}] client.api.get_monitors.return_value = mock_monitors # Same monitor should match both patterns result = client.find_monitors_by_pattern(["Web*", "*Server"]) assert len(result) == 1 assert result[0]["name"] == "Web Server" def test_find_monitors_by_pattern_api_error(self, capsys): """Test finding monitors handles API errors""" from uptime_kuma_api import UptimeKumaException client = KumaClient("http://test.com") client.api = Mock() client.api.get_monitors.side_effect = UptimeKumaException("API Error") result = client.find_monitors_by_pattern(["Web*"]) assert len(result) == 0 captured = capsys.readouterr() assert "Error finding monitors: API Error" in captured.out @patch("kumacli.client.UptimeKumaApi") def test_connect_success(self, mock_api_class, capsys): """Test successful connection""" mock_api = Mock() mock_api_class.return_value = mock_api mock_api.login.return_value = True client = KumaClient("http://test.com", "user", "pass") result = client.connect() assert result is True assert client.api is mock_api mock_api_class.assert_called_once_with("http://test.com") mock_api.login.assert_called_once_with("user", "pass") captured = capsys.readouterr() assert "Connected to http://test.com" in captured.out @patch("kumacli.client.UptimeKumaApi") def test_connect_failure(self, mock_api_class, capsys): """Test connection failure""" from uptime_kuma_api import UptimeKumaException mock_api_class.side_effect = UptimeKumaException("Connection failed") client = KumaClient("http://test.com", "user", "pass") result = client.connect() assert result is False captured = capsys.readouterr() assert "Failed to connect: Connection failed" in captured.out def test_disconnect(self): """Test disconnection""" client = KumaClient("http://test.com") client.api = Mock() client.disconnect() client.api.disconnect.assert_called_once()