Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 2 additions & 0 deletions infrahub_sdk/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ def __init__(self, message: str | None = None, content: str | None = None, url:
self.url = url
if not self.message and self.url:
self.message = f"Unable to decode response as JSON data from {self.url}"
if self.content:
self.message += f". Server response: {self.content}"
super().__init__(self.message)


Expand Down
54 changes: 54 additions & 0 deletions tests/unit/sdk/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import json
import tempfile
import uuid
from pathlib import Path
from unittest.mock import Mock

import pytest
from graphql import parse
from whenever import Instant

from infrahub_sdk.exceptions import JsonDecodeError
from infrahub_sdk.utils import (
base16decode,
base16encode,
base36decode,
base36encode,
calculate_time_diff,
compare_lists,
decode_json,
deep_merge_dict,
dict_hash,
duplicates,
Expand Down Expand Up @@ -227,3 +231,53 @@ def test_calculate_time_diff() -> None:

time5 = Instant.now().subtract(hours=77, minutes=12, seconds=34).format_common_iso()
assert calculate_time_diff(time5) == "3d and 5h ago"


def test_decode_json_success() -> None:
"""Test decode_json with valid JSON response."""
mock_response = Mock()
mock_response.json.return_value = {"status": "ok", "data": {"key": "value"}}

result = decode_json(mock_response)
assert result == {"status": "ok", "data": {"key": "value"}}


def test_decode_json_failure_with_content() -> None:
"""Test decode_json with invalid JSON response includes server content in error message."""
mock_response = Mock()
mock_response.json.side_effect = json.decoder.JSONDecodeError("Invalid JSON", "document", 0)
mock_response.text = "Internal Server Error: Database connection failed"
mock_response.url = "https://example.com/api/graphql"

with pytest.raises(JsonDecodeError) as exc_info:
decode_json(mock_response)

error_message = str(exc_info.value)
assert "Unable to decode response as JSON data from https://example.com/api/graphql" in error_message
assert "Server response: Internal Server Error: Database connection failed" in error_message


def test_decode_json_failure_without_content() -> None:
"""Test decode_json with invalid JSON response and no content."""
mock_response = Mock()
mock_response.json.side_effect = json.decoder.JSONDecodeError("Invalid JSON", "document", 0)
mock_response.text = ""
mock_response.url = "https://example.com/api/graphql"

with pytest.raises(JsonDecodeError) as exc_info:
decode_json(mock_response)

error_message = str(exc_info.value)
assert "Unable to decode response as JSON data from https://example.com/api/graphql" in error_message
# Should not include server response part when content is empty
assert "Server response:" not in error_message


def test_json_decode_error_custom_message() -> None:
"""Test JsonDecodeError with custom message does not override custom message."""
custom_message = "Custom error message"
error = JsonDecodeError(message=custom_message, content="server error", url="https://example.com")

assert str(error) == custom_message
assert error.content == "server error"
assert error.url == "https://example.com"