cd808dc3dd
/ test (push) Successful in 9m10s
Extend CleverSwarm codebase with PDF and Machine and Worker IDs ISSUES CLOSED: #1
851 lines
35 KiB
Python
851 lines
35 KiB
Python
"""
|
|
Unit tests for cleverswarm_client module.
|
|
|
|
Copyright (c) 2016 - present Syncleus, Inc.
|
|
Copyright (c) 2016 - present CleverThis, Inc.
|
|
|
|
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.
|
|
"""
|
|
|
|
import tempfile
|
|
from pathlib import Path
|
|
from unittest.mock import Mock, patch
|
|
import pytest
|
|
import json
|
|
from httmock import HTTMock, urlmatch
|
|
|
|
from cleverswarm_python_client.libs.cleverswarm_client import CleverSwarmClient
|
|
from cleverswarm_python_client.libs.exceptions import (
|
|
InvalidFileException,
|
|
JobNotFoundException,
|
|
UnauthorizedException,
|
|
InvalidUsernameOrPasswordException,
|
|
RequestErrorException,
|
|
ConnectionErrorException,
|
|
ConnectionTimeoutException,
|
|
UnexpectedConditionException,
|
|
)
|
|
from cleverswarm_python_client.libs.job_enums import JobStatus
|
|
from cleverswarm_python_client.libs.file_type_enum import FileTypeAPI
|
|
from cleverswarm_python_client.libs.response_type_enum import ResponseTypeAPI
|
|
|
|
|
|
class TestCleverSwarmClient:
|
|
"""Test cases for CleverSwarmClient."""
|
|
|
|
def setup_method(self):
|
|
"""Set up test client."""
|
|
self.client = CleverSwarmClient("http://localhost:8000/api/v0/")
|
|
|
|
def test_init_with_base_url(self):
|
|
"""Test initialization with base URL."""
|
|
client = CleverSwarmClient("http://localhost:8000/api/v0/")
|
|
assert client._base_url == "http://localhost:8000/api/v0/"
|
|
assert client._username is None
|
|
assert client._token is None
|
|
|
|
def test_init_with_username_and_token(self):
|
|
"""Test initialization with username and token."""
|
|
client = CleverSwarmClient(
|
|
"http://localhost:8000/api/v0/",
|
|
username="testuser",
|
|
token="testtoken"
|
|
)
|
|
assert client._base_url == "http://localhost:8000/api/v0/"
|
|
assert client._username == "testuser"
|
|
assert client._token == "testtoken"
|
|
|
|
def test_init_with_empty_base_url(self):
|
|
"""Test initialization with empty base URL."""
|
|
client = CleverSwarmClient("")
|
|
assert client._base_url == ""
|
|
|
|
def test_init_with_none_base_url(self):
|
|
"""Test initialization with None base URL."""
|
|
client = CleverSwarmClient(None)
|
|
assert client._base_url is None
|
|
|
|
def test_client_initialization_attributes(self):
|
|
"""Test client initialization attributes."""
|
|
client = CleverSwarmClient("http://localhost:8000/api/v0/")
|
|
|
|
# Test all default attributes
|
|
assert client._base_url == "http://localhost:8000/api/v0/"
|
|
assert client._username is None
|
|
assert client._token is None
|
|
assert client._max_retries == 2
|
|
assert client._timeout == 10
|
|
assert client._triplets_template == "{}_output.jsonl"
|
|
|
|
def test_client_initialization_with_credentials(self):
|
|
"""Test client initialization with various credential combinations."""
|
|
# Test with all parameters
|
|
client = CleverSwarmClient(
|
|
"http://localhost:8000/api/v0/",
|
|
username="testuser",
|
|
token="testtoken"
|
|
)
|
|
assert client._username == "testuser"
|
|
assert client._token == "testtoken"
|
|
|
|
def test_client_with_custom_attributes(self):
|
|
"""Test client with custom attributes."""
|
|
client = CleverSwarmClient("http://localhost:8000/api/v0/")
|
|
|
|
# Test that we can modify attributes
|
|
client._max_retries = 5
|
|
client._timeout = 30
|
|
client._triplets_template = "custom_{}_output.jsonl"
|
|
|
|
assert client._max_retries == 5
|
|
assert client._timeout == 30
|
|
assert client._triplets_template == "custom_{}_output.jsonl"
|
|
|
|
def test_file_validation_with_missing_files(self):
|
|
"""Test file validation with missing files."""
|
|
# Test with non-existent files - this should raise InvalidFileException before calling update_token
|
|
# We need to mock the update_token method to avoid the input() call
|
|
with patch.object(self.client, 'update_token'):
|
|
with pytest.raises(InvalidFileException):
|
|
self.client.create_benchmark_job(
|
|
Path("nonexistent1.txt"),
|
|
Path("nonexistent2.json"),
|
|
Path("nonexistent3.jsonl"),
|
|
True
|
|
)
|
|
|
|
def test_file_validation_with_existing_files(self):
|
|
"""Test file validation with existing files."""
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
# Create valid test files
|
|
text_file = Path(temp_dir) / "test.txt"
|
|
json_file = Path(temp_dir) / "test.json"
|
|
jsonl_file = Path(temp_dir) / "test.jsonl"
|
|
|
|
text_file.write_text("Test content")
|
|
json_file.write_text('{"test": "data"}')
|
|
jsonl_file.write_text('{"test": "data"}')
|
|
|
|
# Test that files exist and are valid files
|
|
assert text_file.exists()
|
|
assert text_file.is_file()
|
|
assert json_file.exists()
|
|
assert json_file.is_file()
|
|
assert jsonl_file.exists()
|
|
assert jsonl_file.is_file()
|
|
|
|
# Test that the client can validate these files by calling create_benchmark_job
|
|
# We need to mock the update_token and the HTTP request to avoid actual API calls
|
|
with patch.object(self.client, 'update_token'):
|
|
with patch.object(self.client, '_generic_http_request_executor') as mock_executor:
|
|
# Mock the executor to return the job_id directly
|
|
mock_executor.return_value = "test_job_123"
|
|
|
|
# This should not raise InvalidFileException
|
|
result = self.client.create_benchmark_job(
|
|
text_file, json_file, jsonl_file, True
|
|
)
|
|
|
|
assert result == "test_job_123"
|
|
|
|
def test_client_state_management(self):
|
|
"""Test client state management."""
|
|
client = CleverSwarmClient("http://localhost:8000/api/v0/")
|
|
|
|
# Test initial state
|
|
assert client._token is None
|
|
assert client._username is None
|
|
|
|
# Test setting token
|
|
client._token = "test_token"
|
|
assert client._token == "test_token"
|
|
|
|
# Test setting username
|
|
client._username = "test_user"
|
|
assert client._username == "test_user"
|
|
|
|
def test_client_configuration(self):
|
|
"""Test client configuration options."""
|
|
client = CleverSwarmClient("http://localhost:8000/api/v0/")
|
|
|
|
# Test default configuration
|
|
assert client._max_retries == 2
|
|
assert client._timeout == 10
|
|
|
|
# Test modifying configuration
|
|
client._max_retries = 5
|
|
client._timeout = 30
|
|
|
|
assert client._max_retries == 5
|
|
assert client._timeout == 30
|
|
|
|
def test_triplets_template(self):
|
|
"""Test triplets template functionality."""
|
|
client = CleverSwarmClient("http://localhost:8000/api/v0/")
|
|
|
|
# Test default template
|
|
assert client._triplets_template == "{}_output.jsonl"
|
|
|
|
# Test template formatting
|
|
formatted = client._triplets_template.format("test_job")
|
|
assert formatted == "test_job_output.jsonl"
|
|
|
|
# Test custom template
|
|
client._triplets_template = "custom_{}_result.jsonl"
|
|
formatted = client._triplets_template.format("test_job")
|
|
assert formatted == "custom_test_job_result.jsonl"
|
|
|
|
def test_poll_job_ready_or_failed_completed(self):
|
|
"""Test polling job that is already completed."""
|
|
with patch.object(self.client, 'get_job_status') as mock_status:
|
|
mock_status.return_value = JobStatus.Completed
|
|
|
|
result = self.client.poll_job_ready_or_failed("job123")
|
|
|
|
assert result == JobStatus.Completed
|
|
mock_status.assert_called_once_with("job123")
|
|
|
|
def test_poll_job_ready_or_failed_failed(self):
|
|
"""Test polling job that has failed."""
|
|
with patch.object(self.client, 'get_job_status') as mock_status:
|
|
mock_status.return_value = JobStatus.Failed
|
|
|
|
result = self.client.poll_job_ready_or_failed("job123")
|
|
|
|
assert result == JobStatus.Failed
|
|
mock_status.assert_called_once_with("job123")
|
|
|
|
def test_poll_job_ready_or_failed_processing(self):
|
|
"""Test polling job that is still processing."""
|
|
with patch.object(self.client, 'get_job_status') as mock_status:
|
|
# First call returns Processing, second call returns Completed
|
|
mock_status.side_effect = [JobStatus.Processing, JobStatus.Completed]
|
|
|
|
with patch('time.sleep'): # Mock sleep to speed up test
|
|
result = self.client.poll_job_ready_or_failed("job123")
|
|
|
|
assert result == JobStatus.Completed
|
|
assert mock_status.call_count == 2
|
|
|
|
def test_generic_http_request_executor_success(self):
|
|
"""Test generic HTTP request executor with successful response."""
|
|
def test_func():
|
|
mock_response = Mock()
|
|
mock_response.status_code = 200
|
|
return mock_response
|
|
|
|
result = self.client._generic_http_request_executor(test_func)
|
|
|
|
assert result.status_code == 200
|
|
|
|
def test_generic_http_request_executor_max_retries_exceeded(self):
|
|
"""Test generic HTTP request executor with max retries exceeded."""
|
|
def test_func():
|
|
raise Exception("Persistent failure")
|
|
|
|
with patch('time.sleep'): # Mock sleep to speed up test
|
|
with pytest.raises(Exception):
|
|
self.client._generic_http_request_executor(test_func)
|
|
|
|
def test_job_status_enum_values(self):
|
|
"""Test JobStatus enum values."""
|
|
assert JobStatus.ReadyForProcessing == "ReadyForProcessing"
|
|
assert JobStatus.Processing == "Processing"
|
|
assert JobStatus.Completed == "Completed"
|
|
assert JobStatus.Failed == "Failed"
|
|
|
|
def test_file_type_enum_values(self):
|
|
"""Test FileTypeAPI enum values."""
|
|
assert FileTypeAPI.AutoDetect == "AutoDetect"
|
|
assert FileTypeAPI.Markdown == "Markdown"
|
|
assert FileTypeAPI.PlainText == "PlainText"
|
|
assert FileTypeAPI.PDF == "PDF"
|
|
|
|
def test_response_type_enum_values(self):
|
|
"""Test ResponseTypeAPI enum values."""
|
|
assert ResponseTypeAPI.JsonText == "JsonText"
|
|
assert ResponseTypeAPI.JsonFile == "JsonFile"
|
|
|
|
def test_client_with_different_base_urls(self):
|
|
"""Test client with different base URL formats."""
|
|
# Test with trailing slash
|
|
client1 = CleverSwarmClient("http://localhost:8000/api/v0/")
|
|
assert client1._base_url == "http://localhost:8000/api/v0/"
|
|
|
|
# Test without trailing slash
|
|
client2 = CleverSwarmClient("http://localhost:8000/api/v0")
|
|
assert client2._base_url == "http://localhost:8000/api/v0"
|
|
|
|
# Test with different port
|
|
client3 = CleverSwarmClient("http://localhost:9000/api/v1/")
|
|
assert client3._base_url == "http://localhost:9000/api/v1/"
|
|
|
|
def test_client_initialization_edge_cases(self):
|
|
"""Test client initialization with edge cases."""
|
|
# Test with empty string
|
|
client1 = CleverSwarmClient("")
|
|
assert client1._base_url == ""
|
|
|
|
# Test with None
|
|
client2 = CleverSwarmClient(None)
|
|
assert client2._base_url is None
|
|
|
|
# Test with just username
|
|
client3 = CleverSwarmClient("http://localhost:8000/api/v0/", username="testuser")
|
|
assert client3._username == "testuser"
|
|
assert client3._token is None
|
|
|
|
# Test with just token
|
|
client4 = CleverSwarmClient("http://localhost:8000/api/v0/", token="testtoken")
|
|
assert client4._token == "testtoken"
|
|
assert client4._username is None
|
|
|
|
def test_client_attribute_modification(self):
|
|
"""Test that client attributes can be modified after initialization."""
|
|
client = CleverSwarmClient("http://localhost:8000/api/v0/")
|
|
|
|
# Modify all attributes
|
|
client._base_url = "http://newhost:9000/api/v1/"
|
|
client._username = "newuser"
|
|
client._token = "newtoken"
|
|
client._max_retries = 10
|
|
client._timeout = 60
|
|
client._triplets_template = "new_{}_template.jsonl"
|
|
|
|
# Verify changes
|
|
assert client._base_url == "http://newhost:9000/api/v1/"
|
|
assert client._username == "newuser"
|
|
assert client._token == "newtoken"
|
|
assert client._max_retries == 10
|
|
assert client._timeout == 60
|
|
assert client._triplets_template == "new_{}_template.jsonl"
|
|
|
|
def test_client_string_representation(self):
|
|
"""Test client string representation."""
|
|
client = CleverSwarmClient("http://localhost:8000/api/v0/")
|
|
|
|
# Test that the client object can be converted to string
|
|
client_str = str(client)
|
|
assert isinstance(client_str, str)
|
|
assert "CleverSwarmClient" in client_str
|
|
|
|
def test_client_equality(self):
|
|
"""Test client equality comparison."""
|
|
client1 = CleverSwarmClient("http://localhost:8000/api/v0/")
|
|
client2 = CleverSwarmClient("http://localhost:8000/api/v0/")
|
|
client3 = CleverSwarmClient("http://localhost:9000/api/v0/")
|
|
|
|
# Different instances should not be equal
|
|
assert client1 != client2
|
|
assert client1 != client3
|
|
|
|
# Same instance should be equal to itself
|
|
assert client1 == client1
|
|
|
|
def test_client_hash(self):
|
|
"""Test client hash functionality."""
|
|
client = CleverSwarmClient("http://localhost:8000/api/v0/")
|
|
|
|
# Test that client can be hashed
|
|
client_hash = hash(client)
|
|
assert isinstance(client_hash, int)
|
|
|
|
# Test that same client has same hash
|
|
assert hash(client) == hash(client)
|
|
|
|
def test_client_with_credentials_initialization(self):
|
|
"""Test client initialization with various credential combinations."""
|
|
# Test with both username and token
|
|
client1 = CleverSwarmClient(
|
|
"http://localhost:8000/api/v0/",
|
|
username="user1",
|
|
token="token1"
|
|
)
|
|
assert client1._username == "user1"
|
|
assert client1._token == "token1"
|
|
|
|
# Test with only username
|
|
client2 = CleverSwarmClient(
|
|
"http://localhost:8000/api/v0/",
|
|
username="user2"
|
|
)
|
|
assert client2._username == "user2"
|
|
assert client2._token is None
|
|
|
|
# Test with only token
|
|
client3 = CleverSwarmClient(
|
|
"http://localhost:8000/api/v0/",
|
|
token="token3"
|
|
)
|
|
assert client3._username is None
|
|
assert client3._token == "token3"
|
|
|
|
def test_client_template_functionality(self):
|
|
"""Test client template functionality in detail."""
|
|
client = CleverSwarmClient("http://localhost:8000/api/v0/")
|
|
|
|
# Test default template
|
|
assert client._triplets_template == "{}_output.jsonl"
|
|
|
|
# Test template with different job IDs
|
|
job_ids = ["job1", "job2", "test_job_123", "my-special-job"]
|
|
for job_id in job_ids:
|
|
expected = f"{job_id}_output.jsonl"
|
|
actual = client._triplets_template.format(job_id)
|
|
assert actual == expected
|
|
|
|
# Test custom template
|
|
client._triplets_template = "results_{}_final.jsonl"
|
|
for job_id in job_ids:
|
|
expected = f"results_{job_id}_final.jsonl"
|
|
actual = client._triplets_template.format(job_id)
|
|
assert actual == expected
|
|
|
|
def test_client_retry_configuration(self):
|
|
"""Test client retry configuration."""
|
|
client = CleverSwarmClient("http://localhost:8000/api/v0/")
|
|
|
|
# Test default retry configuration
|
|
assert client._max_retries == 2
|
|
|
|
# Test setting different retry values
|
|
for retries in [0, 1, 5, 10]:
|
|
client._max_retries = retries
|
|
assert client._max_retries == retries
|
|
|
|
def test_client_timeout_configuration(self):
|
|
"""Test client timeout configuration."""
|
|
client = CleverSwarmClient("http://localhost:8000/api/v0/")
|
|
|
|
# Test default timeout
|
|
assert client._timeout == 10
|
|
|
|
# Test setting different timeout values
|
|
for timeout in [1, 5, 30, 60, 120]:
|
|
client._timeout = timeout
|
|
assert client._timeout == timeout
|
|
|
|
|
|
class TestCleverSwarmClientHTTP:
|
|
"""Test cases for CleverSwarmClient HTTP operations using httmock."""
|
|
|
|
def setup_method(self):
|
|
"""Set up test client."""
|
|
self.client = CleverSwarmClient("http://localhost:8000/api/v0/", token="test_token")
|
|
|
|
# Authentication Tests
|
|
@urlmatch(netloc='localhost:8000', path='/api/v0/login', method='POST')
|
|
def login_success_mock(self, url, request):
|
|
"""Mock successful login response."""
|
|
return {
|
|
'status_code': 200,
|
|
'content': json.dumps({
|
|
'access_token': 'new_token',
|
|
'token_type': 'bearer'
|
|
}).encode('utf-8'),
|
|
'headers': {'content-type': 'application/json'}
|
|
}
|
|
|
|
@urlmatch(netloc='localhost:8000', path='/api/v0/login', method='POST')
|
|
def login_unauthorized_mock(self, url, request):
|
|
"""Mock unauthorized login response."""
|
|
return {
|
|
'status_code': 401,
|
|
'content': b'User provided credentials are not correct.',
|
|
'headers': {'content-type': 'text/plain'}
|
|
}
|
|
|
|
@urlmatch(netloc='localhost:8000', path='/api/v0/login', method='POST')
|
|
def login_invalid_credentials_mock(self, url, request):
|
|
"""Mock invalid credentials login response."""
|
|
return {
|
|
'status_code': 400,
|
|
'content': b'Invalid credentials',
|
|
'headers': {'content-type': 'text/plain'}
|
|
}
|
|
|
|
@patch('cleverswarm_python_client.libs.cleverswarm_client.getpass')
|
|
def test_update_token_success(self, mock_getpass):
|
|
"""Test successful token update using httmock."""
|
|
mock_getpass.return_value = "testpassword"
|
|
|
|
with HTTMock(self.login_success_mock):
|
|
client = CleverSwarmClient("http://localhost:8000/api/v0/", username="testuser")
|
|
result = client.update_token()
|
|
|
|
assert result is client # Should return self
|
|
assert client._token == "new_token"
|
|
|
|
@patch('cleverswarm_python_client.libs.cleverswarm_client.getpass')
|
|
def test_update_token_unauthorized(self, mock_getpass):
|
|
"""Test token update with unauthorized response using httmock."""
|
|
mock_getpass.return_value = "testpassword"
|
|
|
|
with HTTMock(self.login_unauthorized_mock):
|
|
client = CleverSwarmClient("http://localhost:8000/api/v0/", username="testuser")
|
|
|
|
with pytest.raises(RequestErrorException, match="Failed process request, error from server"):
|
|
client.update_token()
|
|
|
|
@patch('cleverswarm_python_client.libs.cleverswarm_client.getpass')
|
|
def test_update_token_invalid_credentials(self, mock_getpass):
|
|
"""Test token update with invalid credentials using httmock."""
|
|
mock_getpass.return_value = "testpassword"
|
|
|
|
with HTTMock(self.login_invalid_credentials_mock):
|
|
client = CleverSwarmClient("http://localhost:8000/api/v0/", username="testuser")
|
|
|
|
with pytest.raises(InvalidUsernameOrPasswordException):
|
|
client.update_token()
|
|
|
|
# Job Management Tests
|
|
@urlmatch(netloc='localhost:8000', path='/api/v0/jobs', method='GET')
|
|
def jobs_list_success_mock(self, url, request):
|
|
"""Mock successful jobs list response."""
|
|
return {
|
|
'status_code': 200,
|
|
'content': json.dumps([
|
|
{"id": "job1", "type": "Benchmark", "status": "Completed"},
|
|
{"id": "job2", "type": "UnstructuredWithOntology", "status": "Processing"}
|
|
]).encode('utf-8'),
|
|
'headers': {'content-type': 'application/json'}
|
|
}
|
|
|
|
def test_get_jobs_list_success(self):
|
|
"""Test successful job list retrieval using httmock."""
|
|
with HTTMock(self.jobs_list_success_mock):
|
|
result = self.client.get_jobs_list(is_benchmark=True)
|
|
|
|
assert len(result) == 1 # Only Benchmark jobs are returned
|
|
assert result[0]["id"] == "job1"
|
|
assert result[0]["type"] == "Benchmark"
|
|
|
|
def test_get_jobs_list_filtering(self):
|
|
"""Test job list retrieval with filtering using httmock."""
|
|
with HTTMock(self.jobs_list_success_mock):
|
|
# Test benchmark jobs only
|
|
result = self.client.get_jobs_list(is_benchmark=True)
|
|
assert len(result) == 1
|
|
assert result[0]["type"] == "Benchmark"
|
|
|
|
# Test non-benchmark jobs only
|
|
result = self.client.get_jobs_list(is_benchmark=False)
|
|
assert len(result) == 1
|
|
assert result[0]["type"] == "UnstructuredWithOntology"
|
|
|
|
@urlmatch(netloc='localhost:8000', path=r'/api/v0/jobs/.*', method='GET')
|
|
def job_status_success_mock(self, url, request):
|
|
"""Mock successful job status response."""
|
|
return {
|
|
'status_code': 200,
|
|
'content': json.dumps("Completed").encode('utf-8'),
|
|
'headers': {'content-type': 'application/json'}
|
|
}
|
|
|
|
@urlmatch(netloc='localhost:8000', path=r'/api/v0/jobs/.*', method='GET')
|
|
def job_status_not_found_mock(self, url, request):
|
|
"""Mock job not found response."""
|
|
return {
|
|
'status_code': 404,
|
|
'content': b'Job not found',
|
|
'headers': {'content-type': 'text/plain'}
|
|
}
|
|
|
|
def test_get_job_status_success(self):
|
|
"""Test successful job status retrieval using httmock."""
|
|
with HTTMock(self.job_status_success_mock):
|
|
result = self.client.get_job_status("job123")
|
|
|
|
assert result == JobStatus.Completed
|
|
|
|
def test_get_job_status_not_found(self):
|
|
"""Test job status retrieval for non-existent job using httmock."""
|
|
with HTTMock(self.job_status_not_found_mock):
|
|
with pytest.raises(JobNotFoundException):
|
|
self.client.get_job_status("nonexistent")
|
|
|
|
@urlmatch(netloc='localhost:8000', path=r'/api/v0/jobs/.*', method='GET')
|
|
def job_details_success_mock(self, url, request):
|
|
"""Mock successful job details response."""
|
|
return {
|
|
'status_code': 200,
|
|
'content': json.dumps({
|
|
"id": "job123",
|
|
"status": "Completed",
|
|
"type": "Benchmark",
|
|
"created": "2023-01-01T00:00:00Z"
|
|
}).encode('utf-8'),
|
|
'headers': {'content-type': 'application/json'}
|
|
}
|
|
|
|
def test_get_job_details_success(self):
|
|
"""Test successful job details retrieval using httmock."""
|
|
with HTTMock(self.job_details_success_mock):
|
|
result = self.client.get_job_details("job123")
|
|
|
|
assert result["id"] == "job123"
|
|
assert result["status"] == "Completed"
|
|
|
|
@urlmatch(netloc='localhost:8000', path=r'/api/v0/jobs/.*', method='DELETE')
|
|
def delete_job_success_mock(self, url, request):
|
|
"""Mock successful job deletion response."""
|
|
return {
|
|
'status_code': 200,
|
|
'content': b'Job deleted',
|
|
'headers': {'content-type': 'text/plain'}
|
|
}
|
|
|
|
@urlmatch(netloc='localhost:8000', path=r'/api/v0/jobs/.*', method='DELETE')
|
|
def delete_job_not_found_mock(self, url, request):
|
|
"""Mock job not found for deletion response."""
|
|
return {
|
|
'status_code': 404,
|
|
'content': b'Job not found',
|
|
'headers': {'content-type': 'text/plain'}
|
|
}
|
|
|
|
def test_delete_job_success(self):
|
|
"""Test successful job deletion using httmock."""
|
|
with HTTMock(self.delete_job_success_mock):
|
|
result = self.client.delete_job("job123")
|
|
|
|
assert result is True
|
|
|
|
def test_delete_job_not_found(self):
|
|
"""Test job deletion for non-existent job using httmock."""
|
|
with HTTMock(self.delete_job_not_found_mock):
|
|
with pytest.raises(JobNotFoundException):
|
|
self.client.delete_job("nonexistent")
|
|
|
|
@urlmatch(netloc='localhost:8000', path=r'/api/v0/jobs/.*', method='PUT')
|
|
def retry_job_success_mock(self, url, request):
|
|
"""Mock successful job retry response."""
|
|
return {
|
|
'status_code': 200,
|
|
'content': json.dumps("Processing").encode('utf-8'),
|
|
'headers': {'content-type': 'application/json'}
|
|
}
|
|
|
|
def test_retry_job_success(self):
|
|
"""Test successful job retry using httmock."""
|
|
with HTTMock(self.retry_job_success_mock):
|
|
result = self.client.retry_job("job123")
|
|
|
|
assert result == JobStatus.Processing
|
|
|
|
# File Upload Tests
|
|
@urlmatch(netloc='localhost:8000', path='/api/v0/benchmark', method='POST')
|
|
def benchmark_job_success_mock(self, url, request):
|
|
"""Mock successful benchmark job creation response."""
|
|
return {
|
|
'status_code': 200,
|
|
'content': json.dumps({"job_id": "benchmark_job_123"}).encode('utf-8'),
|
|
'headers': {'content-type': 'application/json'}
|
|
}
|
|
|
|
def test_create_benchmark_job_success(self):
|
|
"""Test successful benchmark job creation using httmock."""
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
# Create valid test files
|
|
text_file = Path(temp_dir) / "test.txt"
|
|
json_file = Path(temp_dir) / "test.json"
|
|
jsonl_file = Path(temp_dir) / "test.jsonl"
|
|
|
|
text_file.write_text("Test content")
|
|
json_file.write_text('{"test": "data"}')
|
|
jsonl_file.write_text('{"test": "data"}')
|
|
|
|
with HTTMock(self.benchmark_job_success_mock):
|
|
with patch.object(self.client, 'update_token'): # Mock update_token to avoid input()
|
|
result = self.client.create_benchmark_job(
|
|
text_file, json_file, jsonl_file, True
|
|
)
|
|
|
|
assert result == "benchmark_job_123"
|
|
|
|
@urlmatch(netloc='localhost:8000', path='/api/v0/unstructured/with_ontology', method='POST')
|
|
def unstructured_job_success_mock(self, url, request):
|
|
"""Mock successful unstructured to KG job creation response."""
|
|
return {
|
|
'status_code': 201,
|
|
'content': json.dumps({"job_id": "unstructured_job_123"}).encode('utf-8'),
|
|
'headers': {'content-type': 'application/json'}
|
|
}
|
|
|
|
def test_create_unstructured_to_kg_job_success(self):
|
|
"""Test successful unstructured to KG job creation using httmock."""
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
# Create valid test files
|
|
text_file = Path(temp_dir) / "test.txt"
|
|
json_file = Path(temp_dir) / "test.json"
|
|
owl_file = Path(temp_dir) / "test.owl"
|
|
|
|
text_file.write_text("Test content")
|
|
json_file.write_text('{"test": "data"}')
|
|
owl_file.write_text('<rdf:RDF>test</rdf:RDF>')
|
|
|
|
with HTTMock(self.unstructured_job_success_mock):
|
|
with patch.object(self.client, 'update_token'): # Mock update_token to avoid input()
|
|
result = self.client.create_unstructured_to_kg_job(
|
|
text_file, json_file, owl_file
|
|
)
|
|
|
|
assert result == "unstructured_job_123"
|
|
|
|
@urlmatch(netloc='localhost:8000', path='/api/v0/unstructured/with_wildcards', method='POST')
|
|
def unstructured_wildcards_job_success_mock(self, url, request):
|
|
"""Mock successful unstructured to KG wildcards job creation response."""
|
|
return {
|
|
'status_code': 201,
|
|
'content': json.dumps({"job_id": "wildcards_job_123"}).encode('utf-8'),
|
|
'headers': {'content-type': 'application/json'}
|
|
}
|
|
|
|
def test_create_unstructured_to_kg_wildcards_job_success(self):
|
|
"""Test successful unstructured to KG wildcards job creation using httmock."""
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
# Create valid test files
|
|
text_file = Path(temp_dir) / "test.txt"
|
|
json_file = Path(temp_dir) / "test.json"
|
|
owl_file = Path(temp_dir) / "test.owl"
|
|
wildcards_file = Path(temp_dir) / "test.wildcards"
|
|
|
|
text_file.write_text("Test content")
|
|
json_file.write_text('{"test": "data"}')
|
|
owl_file.write_text('<rdf:RDF>test</rdf:RDF>')
|
|
wildcards_file.write_text("wildcard1\nwildcard2")
|
|
|
|
with HTTMock(self.unstructured_wildcards_job_success_mock):
|
|
with patch.object(self.client, 'update_token'): # Mock update_token to avoid input()
|
|
result = self.client.create_unstructured_to_kg_wildcards_job(
|
|
text_file, json_file, owl_file, wildcards_file
|
|
)
|
|
|
|
assert result == "wildcards_job_123"
|
|
|
|
# File Download Tests
|
|
@urlmatch(netloc='localhost:8000', path=r'/api/v0/benchmark/.*', method='GET')
|
|
def benchmark_file_download_mock(self, url, request):
|
|
"""Mock successful benchmark file download response."""
|
|
return {
|
|
'status_code': 200,
|
|
'content': b'{"test": "benchmark_data"}',
|
|
'headers': {'content-type': 'application/json'}
|
|
}
|
|
|
|
def test_retrieve_benchmark_files_success(self):
|
|
"""Test successful benchmark files retrieval using httmock."""
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
output_file = Path(temp_dir) / "output.jsonl"
|
|
|
|
with HTTMock(self.benchmark_file_download_mock):
|
|
with patch.object(self.client, 'update_token'): # Mock update_token to avoid input()
|
|
result = self.client.retrieve_benchmark_files("job123", [output_file])
|
|
|
|
assert result == [output_file]
|
|
|
|
@urlmatch(netloc='localhost:8000', path=r'/api/v0/unstructured/.*', method='GET')
|
|
def unstructured_file_download_mock(self, url, request):
|
|
"""Mock successful unstructured file download response."""
|
|
return {
|
|
'status_code': 200,
|
|
'content': b'{"test": "unstructured_data"}',
|
|
'headers': {'content-type': 'application/json'}
|
|
}
|
|
|
|
def test_retrieve_unstructured_to_kg_files_success(self):
|
|
"""Test successful unstructured to KG files retrieval using httmock."""
|
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
output_file = Path(temp_dir) / "output.jsonl"
|
|
|
|
with HTTMock(self.unstructured_file_download_mock):
|
|
with patch.object(self.client, 'update_token'): # Mock update_token to avoid input()
|
|
result = self.client.retrieve_unstructured_to_kg_files("job123", output_file)
|
|
|
|
assert result == output_file
|
|
|
|
# Error Handling Tests
|
|
@urlmatch(netloc='localhost:8000', path='/api/v0/test', method='GET')
|
|
def generic_http_success_mock(self, url, request):
|
|
"""Mock successful generic HTTP response."""
|
|
return {
|
|
'status_code': 200,
|
|
'content': json.dumps({"result": "success"}).encode('utf-8'),
|
|
'headers': {'content-type': 'application/json'}
|
|
}
|
|
|
|
@urlmatch(netloc='localhost:8000', path='/api/v0/test', method='GET')
|
|
def generic_http_error_mock(self, url, request):
|
|
"""Mock error generic HTTP response."""
|
|
return {
|
|
'status_code': 500,
|
|
'content': b'Internal Server Error',
|
|
'headers': {'content-type': 'text/plain'}
|
|
}
|
|
|
|
def test_generic_http_request_executor_success(self):
|
|
"""Test generic HTTP request executor with successful response using httmock."""
|
|
with HTTMock(self.generic_http_success_mock):
|
|
def test_func():
|
|
import requests
|
|
return requests.get("http://localhost:8000/api/v0/test")
|
|
|
|
result = self.client._generic_http_request_executor(test_func)
|
|
|
|
assert result.status_code == 200
|
|
|
|
# Connection Error Tests
|
|
def test_generic_http_request_executor_connection_error(self):
|
|
"""Test generic HTTP request executor with connection error."""
|
|
def test_func():
|
|
import requests
|
|
raise requests.exceptions.ConnectionError("Connection failed")
|
|
|
|
with pytest.raises(ConnectionErrorException):
|
|
self.client._generic_http_request_executor(test_func)
|
|
|
|
def test_generic_http_request_executor_read_timeout_error(self):
|
|
"""Test generic HTTP request executor with read timeout error."""
|
|
def test_func():
|
|
import requests
|
|
raise requests.exceptions.ReadTimeout("Read timeout")
|
|
|
|
with pytest.raises(ConnectionTimeoutException):
|
|
self.client._generic_http_request_executor(test_func)
|
|
|
|
def test_generic_http_request_executor_http_error(self):
|
|
"""Test generic HTTP request executor with HTTP error."""
|
|
def test_func():
|
|
import requests
|
|
raise requests.exceptions.HTTPError("HTTP error")
|
|
|
|
with pytest.raises(RequestErrorException):
|
|
self.client._generic_http_request_executor(test_func)
|
|
|
|
def test_generic_http_request_executor_request_error(self):
|
|
"""Test generic HTTP request executor with request error."""
|
|
def test_func():
|
|
import requests
|
|
raise requests.exceptions.RequestException("Request error")
|
|
|
|
with pytest.raises(UnexpectedConditionException, match="Client error while processing authorization"):
|
|
self.client._generic_http_request_executor(test_func)
|
|
|
|
def test_generic_http_request_executor_unexpected_error(self):
|
|
"""Test generic HTTP request executor with unexpected error."""
|
|
def test_func():
|
|
raise ValueError("Unexpected error")
|
|
|
|
with pytest.raises(UnexpectedConditionException):
|
|
self.client._generic_http_request_executor(test_func)
|