Skip to content

Commit

Permalink
add unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
japdubengsub committed Sep 17, 2024
1 parent 848b982 commit 6278e7e
Show file tree
Hide file tree
Showing 2 changed files with 193 additions and 39 deletions.
74 changes: 36 additions & 38 deletions sdks/python/src/opik/opik_configure.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import logging
from typing import cast
import getpass
from typing import Final, Optional
import logging
from typing import Final, List, Optional, cast

import httpx

import opik.config
from opik import httpx_client
from opik.config import (
OPIK_BASE_URL_LOCAL,
OPIK_BASE_URL_CLOUD,
OPIK_BASE_URL_LOCAL,
OPIK_WORKSPACE_DEFAULT_NAME,
)
from opik.exceptions import ConfigurationError
Expand All @@ -19,6 +17,8 @@
HEALTH_CHECK_URL_POSTFIX: Final[str] = "/is-alive/ping"
HEALTH_CHECK_TIMEOUT: Final[float] = 1.0

URL_WORKSPACE_GET_LIST: Final[str] = "https://www.comet.com/api/rest/v2/workspaces"


def is_interactive() -> bool:
"""
Expand All @@ -30,57 +30,55 @@ def is_interactive() -> bool:

def is_instance_active(url: str) -> bool:
"""
Returns True if given Opik URL responds to an HTTP GET request.
"""
http_client = httpx_client.get(
workspace=OPIK_WORKSPACE_DEFAULT_NAME,
api_key=None,
)
Returns True if the given Opik URL responds to an HTTP GET request.
try:
http_client.timeout = HEALTH_CHECK_TIMEOUT
response = http_client.get(url=url + HEALTH_CHECK_URL_POSTFIX)
Args:
url (str): The base URL of the instance to check.
if response.status_code == 200:
return True
Returns:
bool: True if the instance responds with HTTP status 200, otherwise False.
"""
try:
with httpx.Client(timeout=HEALTH_CHECK_TIMEOUT) as http_client:
response = http_client.get(url=url + HEALTH_CHECK_URL_POSTFIX)
return response.status_code == 200
except httpx.ConnectTimeout:
return False
except Exception:
return False

return False


def is_workspace_name_correct(api_key: str, workspace: str) -> bool:
"""
Returns True if given cloud Opik workspace are correct.
Verifies whether the provided workspace name exists in the user's cloud Opik account.
Raises:
ConnectionError:
"""
Args:
api_key (str): The API key used for authentication with the Opik service.
workspace (str): The name of the workspace to check.
url = "https://www.comet.com/api/rest/v2/workspaces"
Returns:
bool: True if the workspace is found, False otherwise.
client = httpx.Client()
client.headers.update(
{
"Authorization": f"{api_key}",
}
)
Raises:
ConnectionError: Raised if there's an issue with connecting to the Opik service, or the response is not successful.
"""

try:
response = client.get(url=url)
with httpx.Client() as client:
client.headers.update({"Authorization": f"{api_key}"})
response = client.get(url=URL_WORKSPACE_GET_LIST)
except httpx.RequestError as e:
# Raised for network-related errors such as timeouts
raise ConnectionError(f"Network error: {str(e)}")
except Exception as e:
raise ConnectionError(f"Error while checking workspace status: {str(e)}")
raise ConnectionError(f"Unexpected error occurred: {str(e)}")

if response.status_code != 200:
raise ConnectionError(f"Error while checking workspace status: {response.text}")
raise ConnectionError(f"HTTP error: {response.status_code} - {response.text}")

workspaces = response.json()["workspaceNames"]
workspaces: List[str] = response.json().get("workspaceNames", [])

if workspace in workspaces:
return True
else:
return False
return workspace in workspaces


def is_api_key_correct(api_key: str) -> bool:
Expand Down
158 changes: 157 additions & 1 deletion sdks/python/tests/unit/test_opik_configure.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,163 @@
from opik import configure
from unittest.mock import MagicMock, Mock, patch

import httpx
import pytest

from opik.exceptions import ConfigurationError
from opik.opik_configure import configure, is_instance_active, is_workspace_name_correct


@pytest.mark.parametrize(
"status_code, expected_result",
[
(200, True),
(404, False),
(500, False),
],
)
@patch("opik.opik_configure.httpx.Client")
def test_is_instance_active(mock_httpx_client, status_code, expected_result):
"""
Test various HTTP status code responses to check if the instance is active.
"""
mock_client_instance = MagicMock()
mock_response = Mock()
mock_response.status_code = status_code

mock_client_instance.__enter__.return_value = mock_client_instance
mock_client_instance.__exit__.return_value = False
mock_client_instance.get.return_value = mock_response
mock_httpx_client.return_value = mock_client_instance

url = "http://example.com"
result = is_instance_active(url)

assert result == expected_result


@patch("opik.opik_configure.httpx.Client")
def test_is_instance_active_timeout(mock_httpx_client):
"""
Test that a connection timeout results in False being returned.
"""
mock_client_instance = MagicMock()
mock_client_instance.__enter__.return_value = mock_client_instance
mock_client_instance.__exit__.return_value = False
mock_client_instance.get.side_effect = httpx.ConnectTimeout("timeout")

mock_httpx_client.return_value = mock_client_instance

url = "http://example.com"
result = is_instance_active(url)

assert result is False


@patch("opik.opik_configure.httpx.Client")
def test_is_instance_active_general_exception(mock_httpx_client):
"""
Test that any general exception results in False being returned.
"""
mock_client_instance = MagicMock()
mock_client_instance.__enter__.return_value = mock_client_instance
mock_client_instance.__exit__.return_value = False
mock_client_instance.get.side_effect = Exception("Unexpected error")

mock_httpx_client.return_value = mock_client_instance

url = "http://example.com"
result = is_instance_active(url)

assert result is False


@pytest.mark.parametrize(
"api_key, workspace, workspace_names, expected_result",
[
("valid_api_key", "correct_workspace", ["correct_workspace"], True),
("valid_api_key", "incorrect_workspace", ["other_workspace"], False),
("valid_api_key", "empty_workspace", [], False),
],
)
@patch("opik.opik_configure.httpx.Client")
def test_workspace_valid_api_key(
mock_httpx_client, api_key, workspace, workspace_names, expected_result
):
"""
Test cases with valid API keys and workspace verification.
These tests simulate different workspace existence conditions.
"""
# Mock the HTTP response for valid API key cases
mock_client_instance = MagicMock()
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"workspaceNames": workspace_names}

# Mock the context manager behavior
mock_client_instance.__enter__.return_value = mock_client_instance
mock_client_instance.__exit__.return_value = False
mock_client_instance.get.return_value = mock_response
mock_httpx_client.return_value = mock_client_instance

result = is_workspace_name_correct(api_key, workspace)
assert result == expected_result


@pytest.mark.parametrize(
"status_code, response_text",
[(500, "Internal Server Error"), (404, "Not Found"), (403, "Forbidden")],
)
@patch("opik.opik_configure.httpx.Client")
def test_workspace_non_200_response(mock_httpx_client, status_code, response_text):
"""
Test cases where the API responds with a non-200 status code.
These responses should raise a ConnectionError.
"""
# Mock the HTTP response for non-200 status code cases
mock_client_instance = MagicMock()
mock_response = Mock()
mock_response.status_code = status_code
mock_response.text = response_text

mock_client_instance.__enter__.return_value = mock_client_instance
mock_client_instance.__exit__.return_value = False
mock_client_instance.get.return_value = mock_response
mock_httpx_client.return_value = mock_client_instance

api_key = "valid_api_key"
workspace = "any_workspace"

with pytest.raises(ConnectionError):
is_workspace_name_correct(api_key, workspace)


@pytest.mark.parametrize(
"exception",
[
(httpx.RequestError("Timeout", request=MagicMock())),
(Exception("Unexpected error")),
],
)
@patch("opik.opik_configure.httpx.Client")
def test_workspace_request_exceptions(mock_httpx_client, exception):
"""
Test cases where an exception is raised during the HTTP request.
These cases should raise a ConnectionError with the appropriate message.
"""
# Mock the HTTP request to raise an exception
mock_client_instance = MagicMock()
mock_client_instance.__enter__.return_value = mock_client_instance
mock_client_instance.__exit__.return_value = False
mock_client_instance.get.side_effect = exception

mock_httpx_client.return_value = mock_client_instance

api_key = "valid_api_key"
workspace = "any_workspace"

# Check that the appropriate ConnectionError is raised
with pytest.raises(ConnectionError):
is_workspace_name_correct(api_key, workspace)


@pytest.mark.skip
Expand Down

0 comments on commit 6278e7e

Please sign in to comment.