un-inception/clients/python/sync/tests/test_integration_mock.py

258 lines
8.6 KiB
Python

# This is free software for the public good of a permacomputer hosted at
# permacomputer.com, an always-on computer by the people, for the people.
# One which is durable, easy to repair, & distributed like tap water
# for machine learning intelligence.
#
# The permacomputer is community-owned infrastructure optimized around
# four values:
#
# TRUTH First principles, math & science, open source code freely distributed
# FREEDOM Voluntary partnerships, freedom from tyranny & corporate control
# HARMONY Minimal waste, self-renewing systems with diverse thriving connections
# LOVE Be yourself without hurting others, cooperation through natural law
#
# This software contributes to that vision by enabling code execution across 42+ programming languages through a unified interface, accessible to all.
# Code is seeds to sprout on any abandoned technology.
"""Integration tests with mocked API responses"""
from unittest.mock import patch, MagicMock
import json
import pytest
from un import (
execute_code,
execute_async,
get_job,
wait_for_job,
cancel_job,
list_jobs,
get_languages,
)
class TestIntegrationMocked:
"""Integration tests using mocked HTTP responses"""
@patch("un.requests.post")
@patch("un._resolve_credentials")
def test_execute_code_success(self, mock_creds, mock_post):
"""Test successful synchronous code execution"""
mock_creds.return_value = ("pk_test", "sk_test")
# Mock the initial response
mock_response = MagicMock()
mock_response.json.return_value = {
"job_id": "job_123",
"status": "completed",
"stdout": "hello\n",
"stderr": "",
"exit_code": 0,
"runtime_ms": 150,
}
mock_post.return_value = mock_response
result = execute_code("python", "print('hello')")
assert result["status"] == "completed"
assert result["stdout"] == "hello\n"
assert result["exit_code"] == 0
@patch("un.requests.post")
@patch("un._resolve_credentials")
def test_execute_async_returns_job_id(self, mock_creds, mock_post):
"""Test async execution returns job ID"""
mock_creds.return_value = ("pk_test", "sk_test")
mock_response = MagicMock()
mock_response.json.return_value = {
"job_id": "job_456",
"status": "pending",
}
mock_post.return_value = mock_response
job_id = execute_async("javascript", "console.log('hello')")
assert job_id == "job_456"
@patch("un.requests.get")
@patch("un._resolve_credentials")
def test_get_job(self, mock_creds, mock_get):
"""Test getting job status"""
mock_creds.return_value = ("pk_test", "sk_test")
mock_response = MagicMock()
mock_response.json.return_value = {
"job_id": "job_789",
"status": "running",
"created_at": "2024-01-15T10:00:00Z",
}
mock_get.return_value = mock_response
result = get_job("job_789")
assert result["job_id"] == "job_789"
assert result["status"] == "running"
@patch("un.requests.get")
@patch("un.time.sleep")
@patch("un._resolve_credentials")
def test_wait_for_job_completes(self, mock_creds, mock_sleep, mock_get):
"""Test waiting for job to complete"""
mock_creds.return_value = ("pk_test", "sk_test")
# First call: running, second call: completed
mock_responses = [
MagicMock(
json=MagicMock(
return_value={
"job_id": "job_123",
"status": "running",
}
)
),
MagicMock(
json=MagicMock(
return_value={
"job_id": "job_123",
"status": "completed",
"stdout": "result\n",
"exit_code": 0,
}
)
),
]
mock_get.side_effect = mock_responses
result = wait_for_job("job_123")
assert result["status"] == "completed"
assert result["stdout"] == "result\n"
@patch("un.requests.delete")
@patch("un._resolve_credentials")
def test_cancel_job(self, mock_creds, mock_delete):
"""Test cancelling a job"""
mock_creds.return_value = ("pk_test", "sk_test")
mock_response = MagicMock()
mock_response.json.return_value = {
"job_id": "job_123",
"status": "cancelled",
}
mock_delete.return_value = mock_response
result = cancel_job("job_123")
assert result["status"] == "cancelled"
@patch("un.requests.get")
@patch("un._resolve_credentials")
def test_list_jobs(self, mock_creds, mock_get):
"""Test listing jobs"""
mock_creds.return_value = ("pk_test", "sk_test")
mock_response = MagicMock()
mock_response.json.return_value = {
"jobs": [
{"job_id": "job_1", "status": "completed"},
{"job_id": "job_2", "status": "running"},
{"job_id": "job_3", "status": "pending"},
]
}
mock_get.return_value = mock_response
jobs = list_jobs()
assert len(jobs) == 3
assert jobs[0]["job_id"] == "job_1"
assert jobs[1]["status"] == "running"
@patch("un._load_languages_cache")
@patch("un.requests.get")
@patch("un._resolve_credentials")
@patch("un._save_languages_cache")
def test_get_languages_uses_cache(
self, mock_save_cache, mock_creds, mock_get, mock_load_cache
):
"""Test that get_languages uses cache when available"""
mock_load_cache.return_value = ["python", "javascript", "go"]
languages = get_languages()
# Should use cache, not make API call
assert languages == ["python", "javascript", "go"]
mock_get.assert_not_called()
@patch("un._load_languages_cache")
@patch("un.requests.get")
@patch("un._resolve_credentials")
@patch("un._save_languages_cache")
def test_get_languages_fetches_from_api(
self, mock_save_cache, mock_creds, mock_get, mock_load_cache
):
"""Test that get_languages fetches from API when cache misses"""
mock_creds.return_value = ("pk_test", "sk_test")
mock_load_cache.return_value = None # Cache miss
mock_response = MagicMock()
mock_response.json.return_value = {
"languages": ["python", "javascript", "go", "rust"]
}
mock_get.return_value = mock_response
languages = get_languages()
assert len(languages) == 4
assert "python" in languages
mock_save_cache.assert_called_once_with(languages)
@patch("un.requests.post")
@patch("un._resolve_credentials")
def test_request_headers(self, mock_creds, mock_post):
"""Test that requests include proper authentication headers"""
mock_creds.return_value = ("pk_test", "sk_test")
mock_response = MagicMock()
mock_response.json.return_value = {
"job_id": "job_123",
"status": "completed",
}
mock_post.return_value = mock_response
execute_async("python", "print(1)")
# Verify headers were set
call_kwargs = mock_post.call_args[1]
headers = call_kwargs.get("headers", {})
assert "Authorization" in headers
assert headers["Authorization"].startswith("Bearer pk_test")
assert "X-Timestamp" in headers
assert "X-Signature" in headers
assert "Content-Type" in headers
assert headers["Content-Type"] == "application/json"
@patch("un.requests.post")
@patch("un._resolve_credentials")
def test_error_handling_http_error(self, mock_creds, mock_post):
"""Test error handling for HTTP errors"""
mock_creds.return_value = ("pk_test", "sk_test")
mock_response = MagicMock()
mock_response.raise_for_status.side_effect = Exception("404 Not Found")
mock_post.return_value = mock_response
with pytest.raises(Exception):
execute_async("python", "print(1)")
@patch("un.requests.get")
@patch("un._resolve_credentials")
def test_handle_network_timeout(self, mock_creds, mock_get):
"""Test handling of network timeouts"""
import requests
mock_creds.return_value = ("pk_test", "sk_test")
mock_get.side_effect = requests.Timeout("Connection timeout")
with pytest.raises(requests.Timeout):
get_job("job_123")